Interesting Findings
Relationship Between Millennial Population and Internet Access
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from four different data sources: 2007 internet access, 2012 internet access, 2007 population, and 2012 population. The code for this is shown in the screenshot below.
df_1 <- data.world::query(data.world::qry_sql
("SELECT `2007Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS 2007IAHome, `2007Internet_Cleaned`.region as State, `2007population_cleaned`.total_estimate_total_population_age_15_to_19_years as 2007_15_19Population
FROM 2007Internet_Cleaned
JOIN 2007Population_cleaned ON `2007Internet_Cleaned`.region = `2007Population_cleaned`.region"), dataset=project)
df_2 <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS 2012IAHome, `2012Internet_Cleaned`.region as State, `2012population_cleaned`.total_estimate_age_15_to_19_years as 2012_15_19Population
FROM 2012Internet_Cleaned
JOIN 2012Population_cleaned ON `2012Internet_Cleaned`.region = `2012Population_cleaned`.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
As can be seen in the four graphs below, it seems that the percentage of the millennial population with respect to a state is highly correlated with the percentage of individuals who access the internet from home by state in 2007. However, this relationship does not seem to hold as strongly in 2012. In 2007, it is clear that there is discernible relationship as many states that are above the table average for one graph are above the table average for the second graph. For 2012, this does not necessarily seem to be the case.
There could be numerous explanations for this. I believe one possible explanation is as public facilities such as schools started to adapt high speed internet and use it, less and less millennials would access it from home and more and more would start to access it from public facilities. However, this relationship may not hold true going past 2012 as internet as well as devices used to access the internet become more widespread and cheaper.
Means2007 <- df_1 %>% dplyr::summarize(Population_15to19_2007Mean = mean(`2007_15_19Population`), InternetAcess_AtHome_2007Mean = mean(`2007IAHome`))
renderDataTable({
DT::datatable(Means2007, rownames = FALSE,
extensions = list(Responsive = TRUE, FixedHeader = TRUE)
)
})
inputPanel(
selectInput("selectRegiondf_1", label = "Select Region",
choices = df_1$State, multiple=TRUE, selected=df_1$State)
)
renderPlot({df_1 %>% dplyr::select(State,`2007_15_19Population`) %>% dplyr::filter(State == input$selectRegiondf_1) %>% ggplot() + geom_bar(mapping = aes(x=State, y= `2007_15_19Population`), stat="identity") + geom_hline(yintercept=7.26153846153846, color = "blue") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Millennial Population by State (2007)", x="State", y="Population Percentage")})
renderPlot({df_1 %>% dplyr::select(State,`2007IAHome`) %>% dplyr::filter(State == input$selectRegiondf_1) %>% ggplot() + geom_bar(mapping = aes(x=State, y= `2007IAHome`), stat="identity") + geom_hline(yintercept=67.4134615384615, color = "blue") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Average Income by State (2007)", x="State", y="Average Income")})
Means2012 <- df_2 %>% dplyr::summarize(Population_15to19_2012Mean= mean(`2012_15_19Population`), InternetAcess_AtHome_2012Mean = mean(`2012IAHome`))
renderDataTable({
DT::datatable(Means2012, rownames = FALSE,
extensions = list(Responsive = TRUE, FixedHeader = TRUE)
)
})
inputPanel(
selectInput("selectRegiondf_2", label = "Select Region",
choices = df_2$State, multiple=TRUE, selected=df_2$State)
)
renderPlot({df_2 %>% dplyr::select(State,`2012_15_19Population`) %>% dplyr::filter(State == input$selectRegiondf_2) %>% ggplot() + geom_bar(mapping = aes(x=State, y= `2012_15_19Population`), stat="identity") + geom_hline(yintercept = 6.82307692307692, color = "blue")+ theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "Millennial Population by State (2012)", x="State", y="Population Percentage")})
renderPlot({df_2 %>% dplyr::select(State,`2012IAHome`) %>% dplyr::filter(State == input$selectRegiondf_2) %>% ggplot() + geom_bar(mapping = aes(x=State, y= `2012IAHome`), stat="identity") + geom_hline(yintercept = 69.9923076923077, color = "blue") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Average Income by State (2012)", x="State", y="Average Income")})
Relationship Between Income and Users Accessing Internet Outside Home from 2007 to 2012
Inputting the CSV into R
For this insight, I decided to create two data frames containing 2007 and 2012 information on internet access outside the home as well as income. The code for this is shown in the screenshot below. Both data frames will require tidying which will be done through gathering in the step following this.
df_3 <- data.world::query(data.world::qry_sql
("SELECT `2007internet_cleaned`.percent_of_individuals_who_access_internet_outside_of_household as 2007, `2007internet_cleaned`.region as States,
`2012internet_cleaned`.percent_of_individuals_who_access_internet_outside_of_household as 2012
FROM `2007internet_cleaned`
JOIN `2012internet_cleaned`
ON `2007internet_cleaned`.region = `2012internet_cleaned`.region"), dataset=project)
df_4 <- data.world::query(data.world::qry_sql
("SELECT `2007income_cleaned`.average_household_income as `2007`, `2012income_cleaned`.average_household_income as `2012`, `2007income_cleaned`.region as States
FROM 2007income_cleaned JOIN 2012income_cleaned ON `2007income_cleaned`.region = `2012income_cleaned`.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. The code for this is shown below.
df_3 <- df_3 %>%tidyr::gather("Year", "Percentage", -2)
df_4 <- df_4 %>%tidyr::gather("Year", "Income", -3)
Utilizing dplyr to transform, visualize, and communicate
For this insight, I decided to use data from 4 tables: 2007Income, 2012Income, 2007InternetUsage, 2012InternetUsage.
Initially, I was curious to see what the change in internet access outside of the household would be from 2007 to 2012 for different states. Therefore, I decided to create two maps to show this change: one for 2007 and the other for 2012. The maps are shown below. As can be seen, in creating the maps, I used a regular expression to filter out information unique to 2007 and 2012.
df_2007 <- df_3 %>% dplyr::filter(!grepl(".*12$", Year)) %>% dplyr::select(States, Percentage)
names(df_2007) <- c("region", "value")
df_2007$region <- tolower(df_2007$region)
df_2007$region <- gsub(" (u.s. state)", "", df_2007$region, fixed=TRUE)
renderPlot({state_choropleth(df_2007) + labs(title = "Internet Usage Outside Household (2007)")})
df_2013 <- df_3 %>% dplyr::filter(!grepl(".*07$", Year)) %>% dplyr::select(States, Percentage)
names(df_2013) <- c("region", "value")
df_2013$region <- tolower(df_2013$region)
df_2013$region <- gsub(" (u.s. state)", "", df_2013$region, fixed=TRUE)
renderPlot({state_choropleth(df_2013) + labs(title = "Internet Usage Outside Household (2012)")})
As can be seen, it seems that most of the states had relatively the same amount of internet usage from 2007 to 2012 outside the household. However, a few states struck me as having a significant positive change. These states include Idaho and Florida.
I decided to take a look into this further to see if there was any relationship with change in average income from 2007 to 2012. The next plot shows that although most states experienced a change in their average income, relative to one another, they stayed relatively the same.
df_2007Income <- df_4 %>% dplyr::filter(!grepl(".*12$", Year)) %>% dplyr::select(States, Income)
df_2007Income<- df_2007Income %>% dplyr::arrange(Income)
df_2007Income$States <- factor(df_2007Income$States, levels=df_2007Income$States)
renderPlot({df_2007Income %>%ggplot(mapping=aes(x=States, y=Income)) + geom_bar(stat="identity") +theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "Average Income by State (2007 Arranged)", x="State", y="Average Income")})
df_2012Income <- df_4 %>% dplyr::filter(!grepl(".*07$", Year)) %>% dplyr::select(States, Income)
df_2012Income<- df_2012Income %>% dplyr::arrange(Income)
df_2012Income$States <- factor(df_2012Income$States, levels=df_2012Income$States)
renderPlot({df_2012Income %>%ggplot(mapping=aes(x=States, y=Income)) + geom_bar(stat="identity") +theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "Average Income by State (2012 Arranged)", x="State", y="Average Income")})
However, interestingly enough, some states actually had a decrease in their average household income from 2007 to 2012. These states were certainly the minority, and in order to display this relationship more thoroughly, I created a cross tab using a calculated field as well as a parameter. The calculated field was the percentage income difference from 2007 to 2012. The parameter I created accentuated whether or not their was a negative difference in income, a high difference in income, or a medium difference in income. A screenshot of that calculation is shown below.
From my cross tab, I saw that states that had a negative change in their income were ones that had the most increase in internet usage outside the household. These were states such as Idaho and Florida which clearly have a significant positive change in their internet usage outside the household according to first two maps.
My explanation for this is that most likely, states that had a decrease in their average income had less people who could afford to have internet in the house. Thus, they went elsewhere to access the internet. A screenshot of my cross tab is shown below.
inputPanel(
selectInput("selectRegiondf_4", label = "Select Region",
choices = df_4$States, multiple=TRUE, selected= df_4$States)
)
df_4a <- eventReactive(c(input$selectRegiondf_4), {
project <- "https://data.world/apk585/f-17-edv-project-5"
data.world::set_config(cfg_env("DW_API"))
paramQuery <- data.world::qry_sql(
"with q1 as (SELECT ((`2012income_cleaned`.average_household_income - `2007income_cleaned`.average_household_income)/ `2007income_cleaned`.average_household_income) as PercentIncomeDifference, `2007income_cleaned`.region as States
FROM 2007income_cleaned
JOIN 2012income_cleaned ON `2007income_cleaned`.region = `2012income_cleaned`.region)
SELECT q1.PercentIncomeDifference, q1.States,
CASE
WHEN q1.PercentIncomeDifference > 0.05 THEN 'HighAppreciation'
WHEN q1.PercentIncomeDifference < 0.00 THEN 'NegativeChange'
ELSE 'MediumAppreciation'
END AS IncomeParameter
FROM q1
")
paramQuery$params <- c(input$selectRegiondf_4)
data.world::query(paramQuery, dataset = project)
})
renderPlot({df_4a() %>% dplyr::filter(States == input$selectRegiondf_4) %>% ggplot() +
geom_text(aes(x=IncomeParameter, y=States, label=PercentIncomeDifference), size=6) +
geom_tile(aes(x=IncomeParameter, y=States, fill=IncomeParameter), alpha=0.50) +
theme(legend.text=element_text(size=20)) +
theme(axis.text=element_text(size=20),
axis.title=element_text(size=20, face="bold")) +
theme(plot.title = element_text(size = 30, face = "bold")) +
ggtitle(paste("Percent Difference in Average Income from 2007 to 2012")) +
xlab("Income Parameter") + ylab("States")
}, height = 500, width = 1200)
Relationship Between Facebook Penetration and Household Internet Usage - 2007
Inputting the CSV into R
For this insight, I decided to use information from three different data tables: FacebookUsage, 2007AverageIncome, and 2007InternetUsage. I decided to use a left join to join these three tables in order to demonstrate the functionality of the left join. However, a right join or full outer join would have yielded the same result as the region columns all contained the same information for these three data sets. The code for this is shown in the screenshot below.
Additionally, I decided to create a parameter for this insight detailing three different categories: low, medium, and high for the percentage of individuals that accessed the internet from home. This is also shown in the below screenshot.
df_5 <- data.world::query(data.world::qry_sql
("with q1 as (SELECT `2007income_cleaned`.average_household_income as AverageIncome2007, `2007income_cleaned`.region as States, `2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home as AccessInsideHouse2007
FROM `2007income_cleaned`
LEFT JOIN `2007internet_cleaned` ON `2007internet_cleaned`.region = `2007income_cleaned`.region),
q2 as (SELECT q1.AverageIncome2007, q1.States, q1.AccessInsideHouse2007, facebook_cleaned.facebook_penetration as FacebookPenetration
FROM q1
LEFT JOIN `facebook_cleaned` ON `facebook_cleaned`.region = q1.States)
SELECT q2.AverageIncome2007, q2.States, q2.AccessInsideHouse2007, q2.FacebookPenetration,
CASE
WHEN AccessInsideHouse2007 < 59 THEN 'LOW'
WHEN AccessInsideHouse2007 > 70 THEN 'HIGH'
ELSE 'MEDIUM'
END AS LowMediumHighInternetAccess2007
FROM q2"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
The following graph shows that states with low internet usage in home also tended to have a lower average incomes while states with high internet usage tended to have higher average incomes. However, in the middle category, there were two clear discernible outliers that immediately struck me: D.C. and California.
renderPlot({df_5 %>% ggplot() + geom_point(mapping=aes(x=LowMediumHighInternetAccess2007, y=AverageIncome2007, color = States)) + geom_boxplot(mapping=aes(x=LowMediumHighInternetAccess2007, y=AverageIncome2007)) + labs(title = "Average Income by Internet Access at Home (2007)", x="Category of Internet Access", y="Average Income")})
I decided to explore this further and see if I could understand why these outliers existed. I created a set of just these two states and compared their Facebook penetration and internet usage. Interestingly enough, I found that California was on the lower end of the scale while D.C. was completely on the complete opposite side at the very high end of the scale. D.C.’s number struck me as very interesting as the region boasted 260% Facebook penetration.
renderPlot({df_5 %>% dplyr::filter(States %in% c('District of Columbia', 'California')) %>% ggplot(mapping =aes(x=LowMediumHighInternetAccess2007, y=AverageIncome2007, fill=States)) + geom_bar(stat='identity') + facet_wrap(~States)+ labs(title = "Average Income by Internet Access at Home (California / D.C.)", x="Category of Internet Access", y="Average Income")})
renderPlot({df_5 %>% dplyr::filter(States %in% c('District of Columbia', 'California')) %>% ggplot(mapping = aes(x=FacebookPenetration, y=AverageIncome2007, color = States, size = 30)) + geom_point()+ labs(title = "Facebook Penetration With Respect to Average Income (California / D.C.)", x="Facebook Penetration", y="Average Income")})
At first glance, I thought this number was a mistake as it was greater than 100%. To explore this further, I went back to the website I pulled this data set from and found this quote in the footnote: “Please note D.C. penetration data is out of limits, this is probably due to non-resident Facebook users.” Interestingly enough, D.C.’s Facebook penetration number was inflated due to commuters coming into the region, most likely for work. Therefore, the Facebook penetration number was boasted as a multiple of the residential population in D.C.
I found this insight to be even more interesting after I created a table calculation (mutate) of the cumulative sum and cumulative distance of Facebook penetration figures and average household income. There was a very apparent and strong relationship between both figures in both calculations
renderPlot({df_5 %>% dplyr::filter(States != 'District of Columbia' & States != 'California') %>% dplyr::mutate(CumalativeSumFacebook = cumsum(FacebookPenetration), CumalativeSumIncome = cumsum(AverageIncome2007)) %>% ggplot(mapping = aes(x=CumalativeSumFacebook, y=CumalativeSumIncome, color=States)) + geom_point()+ labs(title = "Cumalative Sum of Facebook Penetration (-D.c./-California)", x=" Cumalative Sum of Facebook Penetration", y="Cumalative Sum of Average Income")})
df_5a <- df_5 %>% dplyr::filter(States != 'District of Columbia' & States != 'California') %>% dplyr::mutate(ArrangedCumalativeDistanceFacebook = cume_dist(FacebookPenetration), CumalativeDistanceIncome = cume_dist(AverageIncome2007)) %>% arrange(ArrangedCumalativeDistanceFacebook)
df_5a$States <- factor(df_5a$States, levels=df_5a$States)
renderPlot({df_5a %>% ggplot(mapping = aes(x=ArrangedCumalativeDistanceFacebook, y=CumalativeDistanceIncome, color=States)) + geom_point()+ labs(title = "Cumalative Distance of Facebook Penetration (-D.c./-California)", x=" Cumalative Distance of Facebook Penetration", y="Cumalative Distance of Average Income")})
Relationship Between Facebook Penetration, Internet Penetration, and 20-24 Population - 2012
Inputting the CSV into R
For this insight, I decided to use information from two different data tables: FacebookUsage, and 2012Population. I used an inner join to join these two tables together on region. The code for this is shown in the screnshot below.
df_6 <- data.world::query(data.world::qry_sql
("SELECT `facebook_cleaned`.facebook_penetration as FacebookPenetration, `facebook_cleaned`.internet_penetration as InternetPenetration, `2012population_cleaned`.total_estimate_age_20_to_24_years as Population20to24, `2012population_cleaned`.region as States
FROM `facebook_cleaned`
JOIN 2012population_cleaned on `facebook_cleaned`.region = `2012population_cleaned`.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
A tree map of Facebook penetration relative to internet penetration shows that their doesn’t seem to be a concrete relationship between the two. This is interesting as one would imagine that as internet penetration increases, Facebook penetration would also increase.
df_6a <- df_6 %>% arrange(FacebookPenetration)
df_6a$States <- factor(df_6a$States, levels=df_6a$States)
renderPlot({
ggplot2::ggplot(data=df_6a, mapping = aes(area = FacebookPenetration, fill = InternetPenetration, label=States)) +
geom_treemap() +
geom_treemap_text(fontface = "italic", colour = "white", place = "topleft")+ labs(title = "Tree Map of Facebook Penetration Relative to Internet Penetration (fill = Internet Penetration, area = Facebook Penetration")
})
However, as the second tree map shows, there seems to be a more discernible relationship between Facebook penetration and the population age 20-24 percentage. As that population penetration increases, Facebook penetration seems to also increase. This is clear in states like District of Columbia and North Dakota which have very high percentages of 20-24 year olds as well as a high Facebook penetration. This relationship is most likely attributed to the fact that much of the population on Facebook is young and in between the ages of 19 and 30.
renderPlot({
ggplot2::ggplot(data=df_6a, mapping = aes(area = FacebookPenetration, fill = Population20to24, label=States)) +
geom_treemap() +
geom_treemap_text(fontface = "italic", colour = "white", place = "topleft") + labs(title = "Tree Map of Facebook Penetration Relative to 20-24 Population (fill = 20 to 24 Population, area = Facebook Penetration")
})
Relationship between Male to Female Ratio and Internet Penetration (Blending Data + Ifelse + LOD )
Inputting the CSV into R
For this insight, I used data from two sources: FacebookUsage and 2012Population. In Tableau, I decided to blend these two data sources instead of joining them together. This is shown in the screenshot below.
As can be seen in the above screenshot, both of the data sources have been blended on the region field.
For R documentation purposes, I decided to do an inner join of the two datasets.
For this insight, I also decided to create a view level calculated field that takes the male total population and divides it by the female total population. This is shown as part of the query in the screenshot below.
df_7 <- data.world::query(data.world::qry_sql
("SELECT `facebook_cleaned`.region as States, `facebook_cleaned`.internet_penetration as InternetPenetration, `2012population_cleaned`.male_total_population as MalePopulation, `2012population_cleaned`.female_total_population as FemalePopulation, `2012population_cleaned`.male_total_population / `2012population_cleaned`.female_total_population as MFRatio
FROM `facebook_cleaned`
JOIN `2012population_cleaned` ON `2012population_cleaned`.region = `facebook_cleaned`.region"), dataset=project)
Utilizing dplyr to transform, visualize, and communicate
As the map below shows, it seems that the male to female ratio is least on the east coast and increases slowly as one goes towards the west coast. excluding Oregon and Washington This may be because there are opportunities in the east coast and in those two states that are more attractive to females and vice versa for males. However, it’s very interesting to see that across the whole east coast, females are consistently the majority sex.
Note: to calculate this field in Tableau, I used a fixed LOD calculation. In this following map example, I used group_by by States to do the same thing.
df_7a <- df_7 %>% dplyr::select(States, MFRatio) %>% group_by(States)
names(df_7a) <- c("region", "value")
df_7a$region <- tolower(df_7a$region)
df_7a$region <- gsub(" (u.s. state)", "", df_7a$region, fixed=TRUE)
renderPlot({state_choropleth(df_7a) + labs(title = "Male to Female Ratio by State")})
This next graph shows internet penetration by region. As can be seen, internet penetration seems to be the highest in the north east and in some states on the west coast. such as Oregon and Washington These are also areas that correlate with having lower male to female ratios.
df_7b <- df_7 %>% dplyr::select(States, InternetPenetration) %>% group_by(States)
names(df_7b) <- c("region", "value")
df_7b$region <- tolower(df_7b$region)
df_7b$region <- gsub(" (u.s. state)", "", df_7b$region, fixed=TRUE)
renderPlot({state_choropleth(df_7b)+ labs(title = "Internet Penetration by State")})
However, interestingly enough, areas that are male dominant as shown in the graph below seem to have higher average internet penetration than areas that are female dominant. Therefore, we are most likely missing some sort of key trend / information that explains the relationship in the first two graphs such as a lurking variable.
Note: to calculate whether or not there was a male / female majority, I used the ifelse function under mutate as shown in the screenshot below.
df_7c <- df_7 %>% dplyr::mutate(MFMajority= ifelse(MFRatio<=1, 'FemaleMajority', ifelse(MFRatio>1, 'MaleMajority', 'NA')))
renderPlot({df_7c %>% ggplot() + geom_boxplot(mapping = aes(x=MFMajority, y=InternetPenetration)) + geom_point(mapping = aes(x=MFMajority, y=InternetPenetration, color = States))+labs(title = "Internet Penetration by Male / Female Majority", x=" Male / Female Majority", y="Internet Penetration")})
Relationship between In-home and Out of Home Internet Access for 2007/2012
Inputting the CSV into R
For this insight, I used data from two tables: 2007InternetUsage and 2012InternetUsage. I used an inner join on Tableau in order to join these two tables together on region. However, I used a right join in the following data.world SQL in order to demonstrate its functionality. Because the nomenclature and row values were the same for the column I was joining on, a left join or a inner join would have resulted in the same output.
Additionally, I created a view-level calculated field that takes the sum of the number of people using the internet in home and divides it by the sum of the number of people using the internet out of the home. The following screenshot shows that calculation for 2007 and 2012 data respectively.
df_8 <- data.world::query(data.world::qry_sql
("with `q1` as (SELECT `2007internet_cleaned`.region as States, `2007internet_cleaned`.number_of_individuals_who_access_internet_outside_of_household as 2007AccessOutsideHome, `2007internet_cleaned`.number_of_individuals_who_access_internet_from_home as 2007AccessFromHome,
`2012internet_cleaned`.number_of_individuals_who_access_internet_outside_of_household as 2012AccessOutsideHome, `2012internet_cleaned`.number_of_individuals_who_access_internet_from_home as 2012AccessFromHome
FROM `2007internet_cleaned`
RIGHT JOIN `2012internet_cleaned` on `2007internet_cleaned`.region = `2012internet_cleaned`.region)
SELECT `q1`.States, sum(`q1`.2007AccessFromHome)/sum(`q1`.2007AccessOutsideHome) as AccessRatio2007, sum(`q1`.2012AccessFromHome)/sum(`q1`.2012AccessOutsideHome) as AccessRatio2012
FROM `q1` GROUP BY `q1`.States"),
dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. The code for this is shown below.
df_9 <- df_8 %>%tidyr::gather("YearAccessRatio", "Ratio", -1)
Utilizing dplyr to transform, visualize, and communicate
In the following set of graphs, the plot of 2012 region versus the ratio is the bottom plot while 2007 region versus the ratio is the top plot. As can be seen, for 2012, every single state is below the 1.00 constant line which shows that all states have more people using the internet out of the home than in the home. The plot for 2007 paints a different story where almost every single state is above the 1.00 constant line accentuating that more people use the internet in the home. This development is interesting and is most likely caused by some lurking variable. I believe it may be due to the prevalence of internet usage in the work place over time. This is very counter-intuitive to what I initially thought. I believed that as computers and internet access got cheaper, more people would use it in-home which does not seem to be the case.
Additional note: I used a regular expression on the gathered data frame to filter rows that contained any character, then 12 (2012) as well as any character, then 07 (2007) to get rid of the appropriate rows from the table. The code for that is shown below.
df_8a <- df_9 %>% dplyr::filter(!grepl(".*12", YearAccessRatio)) %>% dplyr::arrange(Ratio)
df_8a$States <- factor(df_8a$States, levels=df_8a$States)
renderPlot({df_8a %>% ggplot(mapping = aes(x=States, y=Ratio, color = States)) + geom_point() + geom_smooth(method = "lm", se=FALSE) + theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "2007 Access From Home to 2007 Access Outside of Home", x="State", y="Access Ratio") + geom_hline(yintercept=1.00, color = "blue")})
df_8b <- df_9 %>% dplyr::filter(!grepl(".*07", YearAccessRatio))%>% dplyr::arrange(Ratio)
df_8b$States <- factor(df_8b$States, levels=df_8b$States)
renderPlot({df_8b %>% ggplot(mapping = aes(x=States, y=Ratio, color = States)) + geom_point() + theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "2012 Access From Home to 2012 Access Outside of Home", x="State", y="Access Ratio") + geom_hline(yintercept=1.00, color = "blue")})
To further back this point, I decided to calculate the pane median in Tableau. With a pane median below 1 for 2012, we see that the “middle” or average state tends to have more people use the internet outside the home as a ratio to in the home. With a pane median above 1 for 2007, we see that the “middle” or average state tends to have more people use the internet in the home as a ratio to outside the home.
MedianRatios <- df_8 %>% summarize(MedianRatio2007 = median(`AccessRatio2007`), MedianRatio2012 = median(`AccessRatio2012`))
renderDataTable({
DT::datatable(MedianRatios, rownames = FALSE,
extensions = list(Responsive = TRUE, FixedHeader = TRUE)
)
})
renderPlot({df_8a %>% ggplot(mapping = aes(x=States, y=Ratio, color = States)) + geom_point() + geom_smooth(method = "lm", se=FALSE) + theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "2007 Access From Home to 2007 Access Outside of Home", x="State", y="Access Ratio") + geom_hline(yintercept=1.05544, color = "blue")})
renderPlot({df_8b %>% ggplot(mapping = aes(x=States, y=Ratio, color = States)) + geom_point() + theme(axis.text.x = element_text(angle = 90, hjust = 1))+ labs(title = "2012 Access From Home to 2012 Access Outside of Home", x="State", y="Access Ratio") + geom_hline(yintercept=0.924915, color = "blue")})
Relationship between Maximum Discrepancy of Internet Access Outside Household and Income Brackets
Inputting the CSV into R
For this insight, I used data from two tables: 2007InternetUsage and 2007Income. I used an inner join on Tableau to join these two data sets together.
In the following screenshot, I created a calculated field in order to bin together regions with low average median incomes, medium average median incomes, and high average median incomes.
df_10 <- data.world::query(data.world::qry_sql
("with `q1` as (SELECT `2007income_cleaned`.average_household_income as AverageIncome, `2007internet_cleaned`.percent_of_individuals_who_access_internet_outside_of_household as OutsideHouse2007, `2007income_cleaned`.region as States
FROM `2007income_cleaned`
JOIN `2007internet_cleaned` ON `2007internet_cleaned`.region = `2007income_cleaned`.region)
SELECT `q1`.States, `q1`.AverageIncome, `q1`.OutsideHouse2007,
CASE
WHEN `q1`.AverageIncome < 60000 THEN 'Low'
WHEN `q1`.AverageIncome > 75000 THEN 'High'
ELSE 'Medium'
END AS IncomeBrackets
FROM `q1`"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
As seen in the following graph, the maximum discrepancy in internet access outside the household does not seem to change as income brackets goes up. This means that the maximum value of a region with internet access outside the household minus the minimum value of a region with internet access outside the household in each income bracket stays relatively the same as income brackets transition from low to high.
I specifically chose percentage of users with internet access outside the household as I initially hypothesized that after a certain income level, the discrepancy in internet usage outside the household among two states would go down. However, I found that there was no real discernible relationship.
The values I calculated were as follows:
Max Access - Min Access Value = Discrepency by Income Bracket Low: 16.7% Medium: 16.4% High: 17.3%
Below is the graph I used to calculate these values
IncomeBracket<- c("Low", "Medium", "High")
MaxDiscrepency <- c("16.7%", "16.4%", "17.3%")
df_11<-data.frame(IncomeBracket, MaxDiscrepency)
renderDataTable({
DT::datatable(df_11, rownames = FALSE,
extensions = list(Responsive = TRUE, FixedHeader = TRUE)
)
})
df_10a <- df_10 %>% dplyr::arrange(OutsideHouse2007)
df_10a$States <- factor(df_10a$States, levels=df_10a$States)
renderPlot({df_10a %>% ggplot(mapping = aes(x=States, y=OutsideHouse2007, color = States)) + geom_point() + facet_wrap(~IncomeBrackets) + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Internet Usage Outside House by Income Bracket (2007)", x="State", y="Outside House Usage")})
Percent of Individuals Who Accessed The Internet from Home in 2007 and 2012
Inputting the CSV into R
df1 <- data.world::query(data.world::qry_sql("SELECT `2012internet_cleaned`.region as region,`2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home as 2007, `2012internet_cleaned`.percent_of_individuals_who_access_internet_from_home as 2012 FROM `2007internet_cleaned` LEFT JOIN `2012internet_cleaned` ON `2007internet_cleaned`.region = `2012internet_cleaned`.region"), dataset = project)
Reformatting in R
df1a <- df1 %>%tidyr::gather("Year", "Percent", -1)
Utilizing dplyr to transform, visualize, and communicate
After the data was joined I chose to analyze the percent of individuals that accessed the internet for each state and compare the year 2007 to 2012. The plots below illustrate two bar charts that show the percent of individuals that accessed the internet from home for both years and also shows the average percent internet usage across all the states. For the year 2007 the average internet usage was 67.21% percent, for the year 2012 the average internet usage was 69.99%. It appears that internet usage increased by 2.78% over a span of 5 years. This is lower than what I expected because many new devices (such as the Apple iPad) came out in that five year period that should have boosted internet usage from home at a higher rate.
inputPanel(
selectInput("selectRegiondf1", label = "Select Region",
choices = df1$region, multiple=TRUE, selected=df1$region)
)
renderPlot({
df1a %>% dplyr::filter(region == input$selectRegiondf1, !grepl(".*12$", Year)) %>%
ggplot() + geom_bar(mapping = aes(x = region, y = Percent),stat="identity", position = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Percent of Individuals who Accessed Internet Data from Home in 2007", x="Region", y="Percent")
})
renderPlot({
df1a %>% dplyr::filter(!grepl(".*07$", Year)) %>%
ggplot() + geom_bar(mapping = aes(x = region, y = Percent),stat="identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Percent of Individuals who Accessed Internet Data from Home in 2012", x="Region", y="Percent")
})
df1b <- df1 %>% dplyr::summarize(`2007AvgPercentInternetUsage` = mean(`2007`), `2012AvgPercentInternetUsage` = mean(`2012`))
renderDataTable({
DT::datatable(df1b, rownames = FALSE,
extensions = list(Responsive = TRUE, FixedHeader = TRUE))
})
Levels of Internet Usage by State and Average Income by State for the Years 2007/2012
Inputting the CSV into R
Querying the data from the 2007 and 2012 internet access data tables has been done the “Utilizing dplyr”" section of this insight because it must be done under the eventReactive function. The query for the barcharts analyzing the average household income data is shown below.
df3a <- data.world::query(data.world::qry_sql("SELECT `2012income_cleaned`.region as region, `2007income_cleaned`.average_household_income as 2007AvgHouseholdIncome,
`2012income_cleaned`.average_household_income as 2012AvgHouseholdIncome
FROM `2007income_cleaned` JOIN `2012income_cleaned` ON `2007income_cleaned`.region = `2012income_cleaned`.region"), dataset = project)
df3b <- data.world::query(data.world::qry_sql("SELECT region, `2007income_cleaned`.average_household_income as 2007AvgHouseholdIncome FROM `2007income_cleaned` WHERE region = 'Alabama' OR region = 'Louisiana' OR region = 'Mississippi' OR region = 'Texas'"), dataset = project)
df3c <- data.world::query(data.world::qry_sql("SELECT region, `2012income_cleaned`.average_household_income as 2012AvgHouseholdIncome FROM `2012income_cleaned` WHERE region = 'Alabama' OR region = 'Louisiana' OR region = 'Mississippi' OR region = 'Texas'"), dataset = project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
To further analyze the data I joined in a previous insight, I decided to create a new discrete variable that looks at low, medium and high internet usage. I queried the data using a CASE statement to replicate the parameters and calculated field I created in Tableau. The query resulted in a new discrete variable so I could analyze low, medium and high usage of the internet from home. The plot below shows the results.
Finally I created two crosstabs to visualize the information for both years. For both years it appears that Mississippi has the lowest percentage of internet usage in the country and New Hampshire has the highest level of usage. Interestingly, Texas, Louisiana, Alabama, and Mississippi all fell under the low usage category for both years. It appears that southern states have the lowest levels of internet usage.
inputPanel(
selectInput("selectRegiondf2", label = "Select Region",
choices = df1$region, multiple=TRUE, selected= df1$region)
)
df2a <- eventReactive(c(input$selectRegiondf2), {
project <- "https://data.world/apk585/f-17-edv-project-5"
data.world::set_config(cfg_env("DW_API"))
paramQuery <- data.world::qry_sql(
"
with q1 as (SELECT `2007internet_cleaned`.region as region, `2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home,
CASE
WHEN `2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home < 62 THEN 'Low'
WHEN `2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home >= 72 THEN 'High'
ELSE 'Medium'
END as usage_level
FROM `2007internet_cleaned`)
SELECT percent_of_individuals_who_access_internet_from_home as Percent2007IAHome, region, usage_level
FROM q1
")
paramQuery$params <- c(input$selectRegiondf2)
data.world::query(paramQuery, dataset = project)
})
renderPlot({df2a() %>% dplyr::filter(region == input$selectRegiondf2) %>% ggplot() +
geom_text(aes(x=usage_level, y=region, label=Percent2007IAHome), size=6) +
geom_tile(aes(x=usage_level, y=region, fill=usage_level), alpha=0.50) +
theme(legend.text=element_text(size=20)) +
theme(axis.text=element_text(size=20),
axis.title=element_text(size=20, face="bold")) +
theme(plot.title = element_text(size = 30, face = "bold")) +
ggtitle(paste("Percent of Individuals who Accessed Internet Data from Home in 2007")) +
xlab("Usage Level") + ylab("Region")
}, height = 500, width = 1200)
df2b <- eventReactive(c(input$selectRegiondf2), {
project <- "https://data.world/apk585/f-17-edv-project-5"
data.world::set_config(cfg_env("DW_API"))
paramQuery <- data.world::qry_sql(
"SELECT `2012internet_cleaned`.region as region, `2012internet_cleaned`.percent_of_individuals_who_access_internet_from_home as Percent2012IAHome FROM `2012internet_cleaned`")
paramQuery$params <- c(input$selectRegiondf2)
data.world::query(paramQuery, dataset = project)
})
renderPlot({df2b() %>% dplyr::filter(region == input$selectRegiondf2) %>% dplyr::mutate(usage_level = ifelse(Percent2012IAHome < 62, 'Low', ifelse(Percent2012IAHome >= 72, 'High', 'Medium'))) %>% ggplot() +
geom_text(aes(x=usage_level, y=region, label=Percent2012IAHome), size=6) +
geom_tile(aes(x=usage_level, y=region, fill=usage_level), alpha=0.50) +
theme(legend.text=element_text(size=20)) +
theme(axis.text=element_text(size=20),
axis.title=element_text(size=20, face="bold")) +
theme(plot.title = element_text(size = 30, face = "bold")) +
ggtitle(paste("Percent of Individuals who Accessed Internet Data from Home in 2012")) +
xlab("Usage Level") + ylab("Region")
}, height = 500, width = 1200)
I decided to look at the income levels for the southern states that have the lowest internet usage so I performed an inner join on region to bring in the average household income for the years 2007 and 2012.
The plots shown below illustrate the average income for households by state. Interestingly, the states with the lowest average income appear to overlap with the states that have the lowest internet usage levels. Some families in these southern states may not be able to afford an internet connection and therefore do not use the internet at home. I created a set of the southern states that fell under the low category and displayed them, the average household income for all four states fall under the national average for the year 2007 and in 2012 Alabama, Mississippi and Louisiana fall under the national average.
inputPanel(
selectInput("selectRegiondf3", label = "Select Region",
choices = df3a$region, multiple=TRUE, selected=df3a$region)
)
renderPlot({
df3a %>% dplyr::filter(region == input$selectRegiondf3) %>% arrange(`2007AvgHouseholdIncome`) %>%
ggplot() + geom_bar(mapping = aes(x = region, y = `2007AvgHouseholdIncome`),stat="identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Average Household Income by State 2007", x="Region", y="Income")
})
renderPlot({
df3b %>% ggplot() +
geom_bar(mapping = aes(x = region, y = `2007AvgHouseholdIncome`, fill = region), stat = "identity") + labs(title = "Average Household Income by State 2007", x="Region", y="Income")
})
renderPlot({
df3a %>% dplyr::filter(region == input$selectRegiondf3) %>%
arrange(`2012AvgHouseholdIncome`) %>%
ggplot() + geom_bar(mapping = aes(x = region, y = `2012AvgHouseholdIncome`),stat="identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Average Household Income by State 2012", x="Region", y="Income")
})
renderPlot({
df3c %>% ggplot() +
geom_bar(mapping = aes(x = region, y = `2012AvgHouseholdIncome`, fill = region), stat = "identity") + labs(title = "Average Household Income by State 2007", x="Region", y="Income")
})
Facebook Penetration and its Relationship to Average Household Income
Inputting the CSV into R
I joined 2012 Facebook data with 2012 Income data using an inner join as can be seen in the query below.
df4 <- data.world::query(data.world::qry_sql("SELECT facebook_cleaned.facebook_penetration as FBPenetration, facebook_cleaned.region as region,
`2012income_cleaned`.average_household_income as AvgHouseholdIncome FROM facebook_cleaned JOIN `2012income_cleaned` ON `2012income_cleaned`.region = facebook_cleaned.region"), dataset = project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
Looking at the Facebook Penetration percentages in the histogram below, it can be seen that the percentage of Facebook usage falls between 36% and 48% for a majority of the states. A few states like Rhode Island, Illinois and Washington state use Facebook at a much higher percentage than the rest of the country.
renderPlot({
df4 %>% dplyr::filter(region != "District of Columbia") %>% ggplot() + geom_histogram(mapping = aes(x = FBPenetration, fill = region), binwidth = 3) + labs(title = "Histogram of Facebook Penetration", x="Facebook Penetration Percent", y="Count")
})
I decided to test whether the average household income had anything to do with Facebook penetration percentages. In a previous insight I found that southern states had the lowest internet usage at home and the same states had some of the lowest averages for household income. Therefore I hypothesized that Facebook usage would be higher in states that have a higher average household income as well because social media is a common use of the internet. According to the plot, Facebook penetration generally appears to increase as the average income increases but there appears to be no clear correlation between the two. This goes against what I initially hypothesized because I expected to see higher social media usage in areas that are more affluent.
It appears that the three states that use Facebook at a higher percentage than the rest of the country (Rhode Island, Illinois, and Washington state) fall slightly above the average Facebook penetration percentage and the average household income for the country but are not among the states with the highest average income in the country as I hypothesized.
renderPlot({
df4 %>% dplyr::filter(region != "District of Columbia") %>% ggplot() + geom_point(mapping = aes(x = AvgHouseholdIncome, y = FBPenetration, color = region)) + labs(title = "Facebook Penetration vs Average Household Income", x="Average Household Income", y="Facebook Penetration")
})
Correlation Between Average Household Income and Internet Penetration
Inputting the CSV into R
Based on the conclusions I arrived to in a previous insight about Facebook Penetration and Average Household Income, I decided to take it a step further and look at Internet Penetration percentages in comparison to the Average Household Income. As can be seen in the query below, I joined the data on the variable “region”.
On tableau I visualized the data by blending it instead of joining it, the screenshot below demonstrates blending the data and establishing a relationship on the base of the variable “region” in both data sets. More information on the blending can be found in the link at the end of the insight.
df5 <- data.world::query(data.world::qry_sql("SELECT `2012income_cleaned`.average_household_income as AvgIncome, facebook_cleaned.region as region, facebook_cleaned.internet_penetration as InternetPenetration
FROM `2012income_cleaned`JOIN facebook_cleaned ON `2012income_cleaned`.region = facebook_cleaned.region"), dataset = project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
I plotted internet penetration percentages against the average household income data. As can be seen in the scatterplot below, at least 50% of the population uses the internet in every state. A general trend line shows that as the average household income increases, the percent of internet penetration increases as well.
renderPlot({
df5 %>% ggplot(mapping = aes(x = AvgIncome, y = InternetPenetration)) + geom_point() + geom_smooth(method = "lm", se = FALSE) + labs(title = "Correlation Between Average Household Income and Internet Penetration", x="Average Income", y="Internet Penetration")
})
An outlier in the data is the District of Columbia which has the highest average household income in the country but falls below the average for internet penetration percentage. To see where DC falls compared to the rest of the country when it comes to internet penetration percentages, I calculated the percent rank for each state in the mutate function. I plotted the state rankings against the states to see how they fell in the range between 0 and 1. It appears that D.C. is ranked .36 which is fairly low for the nation’s capital and center of government operations. Additionally, considering that it is has the highest average household income in the nation, this is an interestingly low ranking for D.C.
renderPlot({
df5 %>% dplyr::mutate(Rank = percent_rank(InternetPenetration)) %>% dplyr::arrange(Rank) %>% ggplot() + geom_point(mapping = aes(x = region, y = Rank)) + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "Percentile Rankings of Internet Usage by State", x="Region", y="Rank")
})
Difference in Income by State for 2007-2012
Inputting the CSV into R
For the following insight I full joined the average household income data for the years 2007 and 2012 on the variable “region.”
df6 <- data.world::query(data.world::qry_sql("SELECT `2012income_cleaned`.region as region, `2012income_cleaned`.average_household_income as 2012, `2007income_cleaned`.average_household_income as 2007
FROM `2007income_cleaned` FULL JOIN `2012income_cleaned` ON `2007income_cleaned`.region = `2012income_cleaned`.region"), dataset = project)
Reformatting in R
df6a <- df6 %>%tidyr::gather("Year", "AverageIncome", -1)
Utilizing dplyr to transform, visualize, and communicate
I created a facet-wrapped bar chart that displays the average household income for each year by region. By looking at this bar chart alone it is difficult to extrapolate information about the difference in income for each state in this five year period. To get around this issue in Tableau I created a level of detail expression that calculates the difference in the income between the years 2007 and 2012 for each state. The screenshot displaying this is below. In R the difference was calculated using the lag function within dplyr mutate.
renderPlot({
df6a %>% dplyr::select(region, Year, AverageIncome) %>%
ggplot() + geom_bar(mapping = aes(x = region, y = AverageIncome), stat = 'identity') + facet_wrap(~Year) + theme(axis.text.x = element_text(angle = 90, hjust = 1)) + labs(title = "A Comparison of Average Household Income for 2007 & 2012", x="Region", y="Average Household Income")
})
df6b <- df6a %>% dplyr::group_by(region) %>% mutate(DifferenceIncome = lag(AverageIncome) - AverageIncome) %>% dplyr::filter(Year == "2007")
As can be seen in the box plot below, over 90% of the states had a positive difference in income indicating that the average household income increased. This could be due to several factors (inflation, changes in local/state taxes, etc). The state with the highest difference in income was North Dakota with a difference of 16 thousand dollars. North Dakota is followed by D.C. which had an income increase of 13 thousand. Both of these states are outliers in the data set. The state with the largest negative difference was Nevada, the average income of which dropped by 6 thousand dollars from 2007 to 2012.
renderPlot({
df6b %>% ggplot() + geom_boxplot(mapping = aes(x = Year, y = DifferenceIncome)) + labs(title = "Difference in Average Household Income 2007/2012", x="", y="Difference in Income")
})
To look at the rest of the states by removing these outliers, I created a map using a color gradient to show the difference in the average income. I removed the three outliers and found that South Dakota had the largest positive difference income and Florida had the largest negative difference. Only four states had a negative change in average income and these states were Florida, Idaho, Arizona and Georgia.
df6c <- df6b %>% dplyr::select(region, DifferenceIncome) %>% dplyr::filter(region != "North Dakota", region != "Nevada", region != "District of Columbia")
names(df6c) <- c("region","value")
df6c$region <- tolower(df6c$region)
df6c$region <- gsub(" (u.s. state", "", df6c$region, fixed = TRUE)
renderPlot({state_choropleth(df6c)})
Internet Usage at Home and its Correlation with the 65-69 Year Old Population
Inputting the CSV into R
For the following insight I inner joined four data frames, population figures for 2007 and 2012 and internet usage figures for 2007 and 2012.
df7 <- data.world::query(data.world::qry_sql("SELECT `2007population_cleaned`.region as region,
`2007internet_cleaned`.percent_of_individuals_who_access_internet_from_home as PercentIAHome,
`2007population_cleaned`.total_estimate_total_population_age_65_to_69_years as Percent65to69Pop, `2007population_cleaned`.total_estimate_total_population_age_30_to_34_years as Percent30to34Pop
FROM `2007internet_cleaned` JOIN `2007population_cleaned` ON `2007internet_cleaned`.region = `2007population_cleaned`.region"), dataset = project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
On tableau, I created a dashboard displaying two packed bubbles plots. For the rmd I created a map instead, but I provided a screenshot of the packed bubbles plot and more information about it can be found in the link at the end of this insight.
The first map displays internet usage at home by state for the year 2007, the second displays the population percent of 65-69 year olds by state. I wanted to look at how the population percent of the 65-69 year olds compares to the percent of people using the internet at home. Based on the plots it appears that the two states (Utah and Alaska) that have the highest percent of internet usage at home also have the lowest percent of 65-69 year olds. The opposite seems to hold true as well, as West Virginia is one of the states with the lowest percentage of internet usage and it has the highest percent of 65-69 year olds in the country.
This general trend makes sense as older people are less likely to use the internet as often as younger people. I decided to compare internet usage percentages against the population percentages of 30-34 year olds by state as well to confirm my hypothesis. Based on the maps shown below the states that have a high percent of internet usage at home have a much higher percent of 30-34 year olds than they do 65-69 year olds.
df7a <- df7 %>% dplyr::select(region, PercentIAHome)
df7b <- df7 %>% dplyr::select(region, Percent65to69Pop)
df7c <- df7 %>% dplyr::select(region, Percent30to34Pop)
names(df7a) <- c("region","value")
df7a$region <- tolower(df7a$region)
df7a$region <- gsub(" (u.s. state", "", df7a$region, fixed = TRUE)
renderPlot({state_choropleth(df7a)})
names(df7b) <- c("region","value")
df7b$region <- tolower(df7b$region)
df7b$region <- gsub(" (u.s. state", "", df7b$region, fixed = TRUE)
renderPlot({state_choropleth(df7b)})
This general trend makes sense as older people are less likely to use the internet as often as younger people. I decided to compare internet usage percentages against the population percentages of 30-34 year olds by state as well to confirm my hypothesis. Based on the maps shown below the states that have a high percent of internet usage at home have a much higher percent of 30-34 year olds than they do 65-69 year olds.
names(df7c) <- c("region","value")
df7c$region <- tolower(df7c$region)
df7c$region <- gsub(" (u.s. state", "", df7c$region, fixed = TRUE)
renderPlot({state_choropleth(df7c)})
Facebook Penetration for 15-19 Year Olds Versus 40-44 Year Olds
Inputting the CSV into R
I decided to join 2012 Facebook data with 2012 Population data to compare the percent of younger people to middle aged adults in regions that have a higher Facebook penetration percentage.
df8 <- data.world::query(data.world::qry_sql("SELECT `2012population_cleaned`.region as region, `2012population_cleaned`.total_estimate_age_15_to_19_years as Percent15to19Population, `2012population_cleaned`.total_estimate_age_40_to_44_years as Percent40to44Population, facebook_cleaned.facebook_penetration as FBPenetration FROM facebook_cleaned JOIN `2012population_cleaned` ON facebook_cleaned.region = `2012population_cleaned`.region"), dataset = project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
Social media is generally a young person’s pass-time but in recent years there has been a surge of middle aged users creating accounts on outlets like Facebook. In some regions the percent of middle aged adults may even exceed the population of younger adults.
I isolated three states with a high Facebook penetration percentage. As can be seen in the plots below, the state of Washington has a very high Facebook penetration percentage. The percent of 15-19 year olds in the state is 6.5% while the percent of 40-44 year olds is higher at 6.8%. New Jersey, another state with a high Facebook penetration percentage, has 6.6% 15-19 year olds and 7.2% 40-44 year olds. Lastly, Alaska has 6.8% 15-19 year olds and 6.9% 40-44 year olds. As hypothesized, the percent of middle aged adults indeed exceeds the population of younger adults.
renderPlot({df8 %>% dplyr::select(region, FBPenetration) %>% dplyr::filter(region %in% c("Washington", "Alaska", "New Jersey")) %>% ggplot() + geom_bar(mapping = aes(x = region, y = FBPenetration, fill = region), stat = "identity") + labs(title = "Facebook Penetration Percent by State", x="Region", y="Percent")
})
renderPlot({df8 %>% dplyr::select(region, Percent15to19Population) %>% dplyr::filter(region %in% c("Washington", "Alaska", "New Jersey")) %>% ggplot() + geom_bar(mapping = aes(x = region, y = Percent15to19Population, fill = region), stat = "identity") + labs(title = "Percent of 15-19 Year Olds by State", x="Region", y="Percent")
})
renderPlot({df8 %>% dplyr::select(region, Percent40to44Population) %>% dplyr::filter(region %in% c("Washington", "Alaska", "New Jersey")) %>% ggplot() + geom_bar(mapping = aes(x = region, y = Percent40to44Population, fill = region), stat = "identity") + labs(title = "Percent of 40-44 Year Olds by State", x="Region", y="Percent")
})
Trends in percent changes between 2007 and 2012 by state of household income and home internet usage (very Interesting)
Inputting the CSV into R
I wanted to analyze the patterns of income and internet usage between 2007 and 2012. Therefore, I joined 2012 and 2007 tables of internet usage in one query and 2012 and 2007 tables of household income in a second query. Since populations could change, I decided to use percents because it was a much easier measure to compare. In the query itself, I created a column that calculated the percent difference of number of home internet users in 2012 versus the number of people in 2007. The second query contained a column that calculated the percent change of average household income in 2012 vs 2007.
df_z <- data.world::query(data.world::qry_sql
("SELECT `2007Internet_cleaned`.number_of_individuals_who_access_internet_from_home AS 2007IAHome,
`2012internet_cleaned`.number_of_individuals_who_access_internet_from_home AS 2012IAHome,
`2007Internet_cleaned`.region as State, (`2012Internet_cleaned`.number_of_individuals_who_access_internet_from_home-`2007Internet_cleaned`.number_of_individuals_who_access_internet_from_home)/`2007Internet_cleaned`.number_of_individuals_who_access_internet_from_home*100 as home_percent_difference
FROM `2012internet_cleaned`
JOIN 2007Internet_cleaned ON `2012Internet_cleaned`.region = `2007Internet_cleaned`.region"), dataset=project)
df_y <- data.world::query(data.world::qry_sql
("SELECT `2007Income_cleaned`.average_household_income AS 2007AVI, `2012Income_cleaned`.average_household_income AS 2012AVI, `2012Income_cleaned`.region as State,
(`2012Income_cleaned`.average_household_income-`2007Income_cleaned`.average_household_income)/`2007Income_cleaned`.average_household_income*100 as income_percent_difference
FROM 2012Income_cleaned
JOIN 2007Income_cleaned ON `2012Income_cleaned`.region = `2007Income_cleaned`.region"), dataset=project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
When looking at the average percent difference between change in income and change in home internet usage, one state stood out in particular. Idaho had a 3.10% decrease in average household income from 2007 to 2012. However, the average number of people who had access to internet at home increased by 34.18%, the largest increase of any state. This seemed highly unusual; however when doing some research, it seemed that Idaho had a program between 2004 and 20014 that widended the scope of internet by increaseing the number of households with broadband. The average household income went down bcause mnay privite sector and tech companies were hireing big time but not a lot of them were located in Idaho.
renderPlot({df_z %>% dplyr::select(State,home_percent_difference)%>% ggplot() + geom_bar(mapping = aes(x=State, y= home_percent_difference, fill = "blue"), stat="identity") + labs(title = "Home Internet Usage Percent Difference by State 2007 - 2012", x="State", y="Percent Change")})
renderPlot({df_y %>% dplyr::select(State,income_percent_difference)%>% ggplot() + geom_bar(mapping = aes(x=State, y= income_percent_difference, fill = "green"), stat="identity") + labs(title = "Average Household Income Percent Difference by State 2007 - 2012", x="State", y="Percent Change")})
Relations between internet usage at home versus internet usage outside of the home from 2007 to 2012
Inputting the CSV into R
I wanted to see the relation between home internet usage and outside the house internet usage in 2007 and 2012. I created two seperate querys, one for 2007 and one for 2012 that pulled the numbe rof individuals who accessed internet from home and from outside of home for each state.
df_w <- data.world::query(data.world::qry_sql
("SELECT `2007Internet_Cleaned`.number_of_individuals_who_access_internet_from_home AS IA_2007_Home,
`2007Internet_Cleaned`.number_of_individuals_who_access_internet_outside_of_household AS IA_2007_Outside,
`2007Internet_Cleaned`.region as State
FROM 2007Internet_Cleaned"), dataset=project)
df_x <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.number_of_individuals_who_access_internet_from_home AS IA_2012_Home,
`2012Internet_Cleaned`.number_of_individuals_who_access_internet_outside_of_household AS IA_2012_Outside,
`2012Internet_Cleaned`.region as State
FROM 2012Internet_Cleaned"), dataset=project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
In 2007, there were actually more people using the internet from home, than there were people using the internet outside of the household. In 2012, the exact opposite is observed. This may be due to advancements in technology and internet efficiency and a wider spread of internet across the globe. More and more small and large businesses began involving more internet based services. For example, coffee shops are now almost expected to have a free internet service, and more people are using this as a place to do work, instead of at home. This most likely drove the number of people using the internet outside the home. It can be seen clearly when comparing to the total US number.
renderPlot({df_w %>% dplyr::select(State,IA_2007_Home,IA_2007_Outside)%>% ggplot() + geom_point(mapping = aes(x=State, y= IA_2007_Home)) + labs(title = "Home internet usage in 2007", x="State", y="Number of users")})
renderPlot({df_w %>% dplyr::select(State,IA_2007_Home,IA_2007_Outside)%>% ggplot() + geom_point(mapping = aes(x=State, y= IA_2007_Outside)) + labs(title = "Outside internet usage in 2007", x="State", y="Number of users")})
renderPlot({df_x %>% dplyr::select(State,IA_2012_Home,IA_2012_Outside)%>% ggplot() + geom_point(mapping = aes(x=State, y= IA_2012_Home)) + labs(title = "Home internet usage in 2012", x="State", y="Number of users")})
renderPlot({df_x %>% dplyr::select(State,IA_2012_Home,IA_2012_Outside)%>% ggplot() + geom_point(mapping = aes(x=State, y= IA_2012_Outside)) + labs(title = "Outside internet usage in 2012", x="State", y="Number of users")})
Facebook users vs mode of Internet usage in 2007
Inputting the CSV into R
I wanted to compare the number of Facebook users of each state to each state’s mode of internet usage. I created two querys, one that pulled the 2007 percents for people who had access to internet at home and outside of home by state and one that pulled the number of facebook users for each state.
df_u <- data.world::query(data.world::qry_sql
("SELECT `2007Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS IA_2007_Home,
`2007Internet_Cleaned`.percent_of_individuals_who_access_internet_outside_of_household AS IA_2007_Outside,
`2007Internet_Cleaned`.region as State
FROM 2007Internet_Cleaned"), dataset=project)
df_t <- data.world::query(data.world::qry_sql
("SELECT facebook_cleaned.faceook_users as users, region as State
from facebook_cleaned"), dataset=project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
I created a line graph that showed the spread of the data by using the dplyr mutate function with cummean. This showed how varied many states were and how each changed the mean of the data set. The final value was the overall mean and that was used to compare to the rest of the charts. I noticed that California with the highest population of Facebook users, was actually below average in both percent of people who used internet at home and outside of home. This is very intriguing because one would think that the place with the most Facebook users would also have a higher level of people using internet from home or from outside of the home; however, that trend is not seen. This may be due to increase of technological advances in other states and California keeping all of its advance in the bay area. Users in other states are more likely to use internet from home than those in California because of the fast-paced life there.
renderPlot({df_t %>% dplyr::filter(State != 'United States')%>% dplyr::mutate(avg_users = cummean(users)) %>% ggplot(mapping = aes(x=State, y=avg_users, group = 1)) + geom_point() + geom_line() + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_t %>% dplyr::filter(State != 'United States')%>% dplyr::mutate(avg_users = cummean(users)) %>% ggplot(mapping = aes(x=State, y=users, fill = avg_users)) + geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_u %>% dplyr::filter(State != 'United States')%>% ggplot(mapping = aes(x=State, y=IA_2007_Home, fill = IA_2007_Home)) + geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_u %>% dplyr::filter(State != 'United States')%>% ggplot(mapping = aes(x=State, y=IA_2007_Outside, fill = IA_2007_Outside )) + geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Facebook users vs mode of Internet usage in 2012
Inputting the CSV into R
I wanted to anayse the previous insight further by looking at more recent data, so I made a similar query but for 2012 numbers for people who had access to internat at home vs out of the home.
df_v <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS IA_2012_Home,
`2012Internet_Cleaned`.percent_of_individuals_who_access_internet_outside_of_household AS IA_2012_Outside,
`2012Internet_Cleaned`.region as State
FROM 2012Internet_Cleaned"), dataset=project)
Reformatting in R
Gathering is not necessary for this insight.
Utilizing dplyr to transform, visualize, and communicate
Further analyzing from a previous insight, I decided to look at 2012 as well to see if there was a relationship there. Since the Facebok data was the same, I used the previous graph and previous average. I created two more graphs that shows the percent of people who use internet outside of the home and percent of people who use the internet at home. It seems as though the California and New York, states with the highest number of Facebook users, actually were below average, even lower than 2007. This is very surprising because it would seem that as time goes on, more and more people would be able to use internet straight from their home. However, since people often work from the office, it makes sense why the percent for usage at home is so low, especially in the cities with a higher industrial tech-savvy base.
renderPlot({df_v %>% dplyr::filter(State != 'United States')%>% ggplot(mapping = aes(x=State, y=IA_2012_Home, fill = IA_2012_Home)) + geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_v %>% dplyr::filter(State != 'United States')%>% ggplot(mapping = aes(x=State, y=IA_2012_Outside, fill = IA_2012_Outside )) + geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Internet Access Vs Average Income Respective to 2007 and 2012
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from four different data sources: 2007 internet access, 2012 internet access, 2007 income, and 2012 income. The code for this is shown in the screenshot below.
df_a <- data.world::query(data.world::qry_sql
("SELECT `2007Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS 2007IAHome,
`2007Internet_Cleaned`.region as State,
`2007income_cleaned`.average_household_income as AVG_Income2007
FROM 2007Internet_Cleaned
JOIN `2007income_cleaned` ON `2007Internet_Cleaned`.region = `2007income_cleaned`.region"), dataset=project)
df_b <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS 2012IAHome,
`2012Internet_Cleaned`.region as State,
`2012income_cleaned`.average_household_income as AVG_Income2012
FROM 2012Internet_Cleaned
JOIN `2012income_cleaned` ON `2012Internet_Cleaned`.region = `2012income_cleaned`.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate The two scatterplots compares internet access to average income with respect to State as well for both years 2007 and 2012. At first glance, we see that there is a strong, positive, linear correlation between internet access and average income. As seen in the data below, the States with “high” national average income have the highest percentage of internet access and the States with “low” national average income have the lowest percentage of internet access. This is expected as States with weathier inhabitants can more likely afford internet services, thus the higher internet penetration and vise versa. However, it is interesting to see that the correlation between internet access and average income is significantly weaker in the year of 2012 and more scattered. Furthermore, the slope of average income versus internet access is a lot less steep indicating States with lower average income increasingly high percentages of internet access relative to the 2007 distribution. Thus one can conclude that within the 5 year time frame, the affordability of internet access is on the rise. This can be projected long term as when as technology advancements increase overtime, cause the price of past technologies to decrease.
renderPlot({df_a %>% ggplot(mapping = aes(x=`2007IAHome`, y=`AVG_Income2007`, color=State)) + geom_point()+ labs(title = "2007 Internet Acess vs Average Income", x="Internet Access", y="Average Income")})
renderPlot({df_b %>% ggplot(mapping = aes(x=`2012IAHome`, y=`AVG_Income2012`, color=State)) + geom_point()+ labs(title = "2012 Internet Access vs Average Income", x="Internet Access", y="Average Income")})
To further analyze State average income’s direct effect on internet and Facebook penetration I create two parameters, Low Income and High Income based on the above visualization. With these parameters, I utilize the Calculated Field to create a custom dimension, “Level of National Average Income.” Utilizing this dimension in tandem with Regions, I created a crosstabs to compare income with Internet penetration. As seen in the data below, the States with “high” national average income have the highest internet penetration and the States with “low” national average income have the lowest internet penetration. Thus one can conclude that there is a strong, linear, positive correlation between income and internet penetration. This is expected as States with weathier inhabitants can afford to internet services, thus the higher internet penetration and vise versa.
Similarly, we analyze the each State’s average income’s effect on Facebook penetration using the same parameters and calculated fields aforementioned. We see the pattern is the same. States with “low” national average income have the lowest Facebook penetration, whereas States with “high” national average income have the high Facebook penetration. This exemplifies a strong, linear, positive correlation between income and Facebook penetration as well. This validates the conclusion drawn above as poorer inhabitants are less likely to be able to afford internet services, lowering the internet penetration and in return lowering Facebook penetration because one cannot access Facebook without internet access.
Internet Penetration Vs Facebook Penetration Vs Internet Access
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from three different data sources: internet penetration, Facebook penetration, and internet access percentage. The code for this is shown in the screenshot below.
df_aa <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS InternetAccess2,
`2012Internet_Cleaned`.region as State,
facebook_cleaned.facebook_penetration as FB_Pen2
FROM 2012Internet_Cleaned
JOIN facebook_cleaned ON `2012Internet_Cleaned`.region = facebook_cleaned.region"), dataset=project)
df_c <- data.world::query(data.world::qry_sql
("SELECT facebook_cleaned.internet_penetration as NET_Pen,
facebook_cleaned.facebook_penetration as FB_pen,
facebook_cleaned.region as State
FROM Facebook_Cleaned"), dataset=project)
df_d <- data.world::query(data.world::qry_sql
("SELECT `2012internet_cleaned`.percent_of_individuals_who_access_internet_from_home as IAhome,
`2012internet_cleaned`.percent_of_individuals_who_access_internet_outside_of_household as IAoutside,
`2012internet_cleaned`.region as State
FROM 2012internet_cleaned"), dataset=project)
df_e <- data.world::query(data.world::qry_sql
("SELECT `2012Internet_Cleaned`.percent_of_individuals_who_access_internet_from_home AS InternetAccess,
`2012Internet_Cleaned`.region as State,
facebook_cleaned.internet_penetration as NET_Pen2
FROM 2012Internet_Cleaned
JOIN facebook_cleaned ON `2012Internet_Cleaned`.region = facebook_cleaned.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
First I compare the percent tiles of individuals who has access to internet of inside of household to the percentage of individuals who have access to internet outside of household. As expected, I can see that there is a extremely strong, positive, linear correlation between the two variables. One can assume that people with access to internet from home should have access to internet outside of home as well. Furthermore, one can assume these two variables can be used interchangeably now.
renderPlot({df_d %>%
ggplot() +
geom_histogram(mapping = aes(x=`IAhome`, fill = State), bins = 10) +
labs(title = "Percent of the Populace with Internet Access From Home Respective to State", x="Percent of Internet Access From Home", y="Count")})
renderPlot({df_d %>%
ggplot() +
geom_histogram(mapping = aes(x=`IAoutside`, fill = State), bins = 10) +
labs(title = "Percent of the Populace with Internet Access From Outside of Home Respective to State", x="Percent of Internet Access From Home", y="Count")})
Facebook penetration is the ratio of Facebook users to population and internet penetration is measures internet users to population.Looking at the Internet versus Facebook Penetration plot, one can see that the District of Columbia is an extreme outlier for Facebook penetration. However, when it comes to Internet penetration, D.C. has a normalized value. Upon further analysis, there appears to be a positive, linear correlation between Internet penetration and Facebook penetration. This is expected, as one should expect that areas with higher internet penetration should have a higher Facebook penetration. However, interesting enough the correlation between the two is not strong at all, perhaps fewer people use Facebook than one would typically imagine. Analyzing the Internet Penetration versus we see that there is in fact a direct positive correspondence between percentage of internet access and internet penetration. This is expected as areas with high internet access percentages, should have higher internet penetration as population is a factor in both. Seen that there is internet penetration and internet access percentages are homogeneous in nature, we can conclude that aforementioned analysis on internet access can be directly applied to internet penetration as well and vise versa.
renderPlot({df_c %>% ggplot(mapping = aes(x=`NET_Pen`, y=`FB_pen`, color=State)) + geom_point()+ labs(title = "Internet Penetration vs Facebook Penetration", x="Internet Penetration", y="Facebook Penetration")})
renderPlot({df_aa %>% ggplot(mapping = aes(x=`InternetAccess2`, y=`FB_Pen2`)) + geom_point() + geom_smooth(method = "lm", se = FALSE) + labs(title = "Internet Penetration vs Internet Access", x="Internet Access", y="Internet Penetration")})
renderPlot({df_e %>% ggplot(mapping = aes(x=`InternetAccess`, y=`NET_Pen2`)) + geom_point() + geom_smooth() + labs(title = "Internet Penetration vs Internet Access", x="Internet Access", y="Internet Penetration")})
Gender Vs Facebook Penetration
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from two different data sources: population (male, female and total) and Facebook penetration. The code for this is shown in the screenshot below.
df_f <- data.world::query(data.world::qry_sql
("SELECT `2012population_cleaned`.female_total_population as female_pop,
`2012population_cleaned`.total_population as total_pop,
facebook_cleaned.facebook_penetration as FB_Pen2,
`2012population_cleaned`.region as State
FROM 2012population_cleaned
JOIN facebook_cleaned ON `2012population_cleaned`.region = facebook_cleaned.region"), dataset=project)
df_g <- data.world::query(data.world::qry_sql
("SELECT `2012population_cleaned`.male_total_population as male_pop,
`2012population_cleaned`.total_population as total_pop,
facebook_cleaned.facebook_penetration as FB_Pen2,
`2012population_cleaned`.region as State
FROM 2012population_cleaned
JOIN facebook_cleaned ON `2012population_cleaned`.region = facebook_cleaned.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
Interesting enough, regarding Facebook Penetration, we see that the Delaware ranked the lowest. If wealth and population size are contributing factors to Facebook Penetration, it is odd to see Delaware ranked the lowest. Only 12% of Delaware’s population is below the poverty level, whereas 16% of the national population is below the poverty level. The population size of Delaware is 900,000 portraying that Delaware is both economically well off and smaller in population compared to other States. However, one would expect such a State to have higher Facebook penetration.
Given that the District of Columbia is an extreme outlier, I extrapolate it. Then I take into consideration, gender by creating calculated fields, which I implement by utilizing mutate as seen below, to denote the percentage of gender type respective to each State. First I create two line plots, to visualize the gender discrepency relative to each State. As seen below, the variance is significant enough to proceed with analysis. Analyzing further by implementing bargraphs that incorporate gender as a fill. This allows us to differentiate Facebook penetration relative to gender type. Looking at the distribution, I see that the top 5 States ranked highest in Facebook penetration are D.C., Georgia, Illinois, Rhode Island and Washington. Interesting enough, all five of those States have a greater female population as seen in the plots below. One may conclude that gender has a direct effect on Facebook penetration.
renderPlot({df_f %>% dplyr::filter(State != 'District of Columbia')%>% dplyr::mutate(percentFemale = ((`female_pop`)/(`total_pop`))*100) %>% ggplot(mapping = aes(x=State, y=percentFemale, group = 1)) + geom_point() + geom_line() + labs(title = "Female Population Percentage Distribution")+ theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_f %>% dplyr::filter(State != 'District of Columbia')%>% dplyr::mutate(percentFemale = ((`female_pop`)/(`total_pop`))*100) %>% ggplot() + geom_bar(aes(State, `FB_Pen2`, fill = percentFemale), position = "dodge", stat="identity") + labs(title = "Facebook Penetration with Respect to Percentage of Female Population", y="Facebook Penetration") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_g %>% dplyr::filter(State != 'District of Columbia')%>% dplyr::mutate(percentMale = ((`male_pop`)/(`total_pop`))*100) %>% ggplot(mapping = aes(x=State, y=percentMale, group = 1)) + geom_point() + geom_line() + labs(title = "Male Population Percentage Spread") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
renderPlot({df_g %>% dplyr::filter(State != 'District of Columbia')%>% dplyr::mutate(percentMale = ((`male_pop`)/(`total_pop`))*100) %>% ggplot() + geom_bar(aes(State, `FB_Pen2`, fill = percentMale), position = "dodge", stat="identity") + labs(title = "Facebook Penetration with Respect to Percentage of Male Population", y="Facebook Penetration") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Younger Age Group (15-29) Vs Facebook Penetration
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from two different data sources: Age groups of population and Facebook penetration. The code for this is shown in the screenshot below.
df_h <- data.world::query(data.world::qry_sql
("SELECT `2012population_cleaned`.total_estimate_age_15_to_19_years as age15_19,
`2012population_cleaned`.total_estimate_age_20_to_24_years as age20_24,
`2012population_cleaned`.total_estimate_age_25_to_29_years as age25_29,
`2012population_cleaned`.total_population as totalPop,
facebook_cleaned.facebook_penetration as FB_PEN,
`2012population_cleaned`.region as State
FROM 2012population_cleaned
JOIN facebook_cleaned ON `2012population_cleaned`.region = facebook_cleaned.region"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate One of the stereotypes in society is that younger people (teenagers and young adults) are more tech savvy and are a vast majority of the social media scene. In this insight I am deciding to test if the stereotype holds any truth. Specifically, I analyzed Facebook penetration and age group 15-29. I created a calculated field, by implementing R’s mutate function, to configure the percentage the younger custom age group that I created, respective to the total population to each respective State. As seen previously, D.C. was an immense outlier and had the highest Facebook penetration respective to other States. Based on the plot below, I can conclude that D.C. has the most amount of individuals within the age group 15-29 respective to population since it had the highest “Young Age Group,” percentage compared to other states, thus exemplifying said stereotype.
renderPlot({df_h %>% dplyr::filter(State != 'United States')%>% dplyr::mutate(younger = ((`age15_19` + `age20_24` + `age25_29`)/(`totalPop`))*100) %>% ggplot() + geom_bar(aes(State, younger), position = "dodge", stat="identity") + labs(title = "Population Percentage of Custom Age Group (15-29) by State", y="Percentage of Age Group 15-29") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Examining the younger age group, we see that the top 5 States with the highest percentage of ages 15-29, are D.C., Wyoming, North Dakota, Vermont, and Alaska. Interesting enough we see that among the set of states, only DC is apart of the top 5 Facebook penetration States.
renderPlot({df_h %>% dplyr:: filter(State %in% c("Alaska", "District of Columbia", "North Dakota", "Vermont", "Wyoming"))%>% dplyr::mutate(younger = ((`age15_19` + `age20_24` + `age25_29`)/(`totalPop`))*100) %>% ggplot() + geom_bar(aes(State, younger, fill = "#FF6666"), position = "dodge", stat="identity") + labs(title = "The Five Highest Population Percentage of Age Group (15-29)", y="Percentage of Age Group 15-29") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
We analyzing further by incorporating Facebook penetration directly into our data analysis. Given that the District of Columbia is an extreme outlier, we extrapolate it and further analyze Facebook penetration with respect to the younger age group of 15-29. Based on the screenshot below, we now realize that although only DC was apart of the top 5 Facebook penetration States, the top 4 States with the highest percentage of ages 15-29 have high Facebook penetration as well, just not the highest. Thus one can conclude that age is a factor when it comes to the social media scene, just not as overwhelming as it is portrayed in society.
renderPlot({df_h %>% dplyr:: filter(State != "District of Columbia") %>% dplyr::mutate(younger = ((`age15_19` + `age20_24` + `age25_29`)/(`totalPop`))*100) %>% ggplot() + geom_bar(aes(State, younger, fill = `FB_PEN`), position = "dodge", stat="identity") + labs(title = "Facebook Penetration with Respect to Population Percentage of Custom Age Group (15-29)", y="Percentage of Age Group 15-29") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Investigating further, it is extremely odd, and interesting to see that Georgia, Illinois, and Washington (part of the Top 5 Facebook penetration States), had extremely low percentages of ages 15-29 respective to each State’s population. Similarly, it is odd to see that Delaware, the State with the lowest, Facebook penetration, as mentioned previously, has a pretty high percentage of age 15-29 individuals. Both of these aforementioned details are counter intuitive to what the data has shown up until now. This could mean that there are bigger variables at play effecting Facebook penetration or these are merely exceptions or age is not as big of a factor as imagined.
renderPlot({df_h %>% dplyr:: filter(State %in% c("Delaware", "Georgia", "Illinois", "Washington")) %>% dplyr::mutate(younger = ((`age15_19` + `age20_24` + `age25_29`)/(`totalPop`))*100) %>% ggplot() + geom_bar(aes(State, younger, fill = `FB_PEN`), position = "dodge", stat="identity") + labs(title = "Facebook Penetration with Respect to Population Percentage of Custom Age Group (15-29)", y="Percentage of Age Group 15-29") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
Elderly Age Group (60-85+) Vs Facebook Penetration
Inputting the CSV into R
In this step, I used the data.world non-select * SQL to create two tibbles containing columns from two different data sources: Age groups of population and Facebook penetration. The code for this is shown in the screenshot below.
df_i <- data.world::query(data.world::qry_sql
("SELECT `2012population_cleaned`.total_estimate_age_60_to_64_years as age60_64,
`2012population_cleaned`.total_estimate_age_65_to_69_years as age65_69,
`2012population_cleaned`.total_estimate_age_70_to_74_years as age70_74,
`2012population_cleaned`.total_population as totalPOP,
facebook_cleaned.facebook_penetration as FB_pen,
`2012population_cleaned`.region as State
FROM 2012population_cleaned
JOIN facebook_cleaned ON `2012population_cleaned`.region = facebook_cleaned.region
"), dataset=project)
Reformatting in R
The next step in the data science pipeline is to gather the columns into a set of key value pairs. However, for this current insight, gathering was not needed.
Utilizing dplyr to transform, visualize, and communicate
Having analyzed and somewhat validated that the majority of social media users are among the younger age groups, I analyze the elder age group to check if it matches the outcome and to test the alternative stereotype that elderly make up the vast minority of social media users. I create a calculated field, by implementing R’s mutate function to that calculates the percentage of elders 60-85+ years of age respective to population per State. At initial glance, I see that D.C. is not among the top 3 States with the largest percentage of ages 60-85+ individuals, this is expected as the State with the highest Facebook penetration should have more younger population if the stereotypes are true.
renderPlot({df_i %>% dplyr::filter(State != 'District of Columbia')%>% dplyr::mutate(elder = ((`age60_64` + `age65_69` + `age70_74`)/(`totalPOP`))*100) %>% ggplot() + geom_bar(aes(State, elder, fill = `FB_pen`), position = "dodge", stat="identity") + labs(title = "Facebook Penetration with Respect to Population Percentage of Custom Age Group (60-85+) by State", y="Percentage of Age Group 60-85+") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
After extrapolating the outlier DC, I implement a tree map to gain more perspective. I that the six States with the highest percentage 60-85+ population (ranked by size), are Vermont, Wyoming, North Dakota, South Dakota, Delaware, and Montana. Of the six States, four of which have lower Facebook penetration, with Wyoming and North Dakota being exceptions. Most importantly, we see that Delaware, the State with the absolute lowest Facebook penetration is among the States with the highest percentage of elderly population (60-85+ years of age), thus validating our previous outcome on the younger age group. Taking a look at the distributed pattern of Facebook penetration relative to the elderly age tree map, we see that the vast majority of high Facebook penetration are among the smaller sized tiles indicating, States with much lower percentages of elderly population have higher Facebook penetration, thus exemplifying the stereotype as well. Consequently, one can conclude, that age does play a significant factor in Facebook penetration, social media usage. However, we again see some oddities in our data. We see that Wyoming and North Dakota have pretty high Facebook penetration, but are part of the States with the largest elderly population, thus signifying that there are other variables at play as well.
renderPlot({
ggplot2::ggplot(data=df_i %>% dplyr::mutate(elder = ((`age60_64` + `age65_69` + `age70_74`)/(`totalPOP`))*100) %>% arrange(elder) %>% dplyr::filter(State != 'District of Columbia'), mapping = aes(area = elder, fill = FB_pen, label=State)) +
geom_treemap() +
geom_treemap_text(fontface = "italic", colour = "white", place = "topleft")+ labs(title = "Tree Map of Population of Elder Age Group (60-85+) Relative to Facebook Penetration (fill = Facebook Penetration, area = Population Percentage of Age Group 60-85+")
})
renderPlot({df_i %>% dplyr:: filter(State %in% c("Vermont", "South Dakota", "North Dakota", "Delaware", "Wyoming", "Montana"))%>% dplyr::mutate(elder = ((`age60_64` + `age65_69` + `age70_74`)/(`totalPOP`))*100) %>% ggplot() + geom_bar(aes(State, elder, fill = `FB_pen`), position = "dodge", stat="identity") + labs(title = "The Six Lowest Population Percentage of Age Group (60-85+)", y="Percentage of Age Group 60-85+") + theme(axis.text.x = element_text(angle = 90, hjust = 1))})
LS0tDQp0aXRsZTogIkFuYWx5emluZyBJbnRlcm5ldCBBY2Nlc3MsIFBvcHVsYXRpb24sIEluY29tZSwgYW5kIEZhY2Vib29rIERhdGEgT3ZlciBUaW1lIg0KYXV0aG9yOiAiSmFtZXMgTGluIg0KcmVzb3VyY2VfZmlsZXM6DQotIC5SZW52aXJvbg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCnJ1bnRpbWU6IHNoaW55DQotLS0NCg0KIyAqKkludHJvZHVjdGlvbioqDQpUaGUgcHVycG9zZSBvZiB0aGlzIHByb2plY3QgaXMgdG8gZGVtb25zdHJhdGUga25vd2xlZGdlIG9mIHRoZSBjb21wbGV0ZSBkYXRhIHNjaWVuY2UgcGlwZWxpbmUgYW5kIHVzZSB0ZWNobmlxdWVzIGxlYXJuZWQgaW4gY2xhc3MgdG8gZXh0cmFjdCBpbnRlcmVzdGluZyBpbnNpZ2h0cyBmcm9tIGEgcGFydGljdWxhciBkYXRhIHNldC4gDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRhdGEud29ybGQpDQpyZXF1aXJlKGRhdGEud29ybGQpDQpsaWJyYXJ5KHNoaW55KQ0KbGlicmFyeSh0cmVlbWFwaWZ5KQ0KbGlicmFyeSh0aWJibGUpDQpyZXF1aXJlKERUKQ0KbGlicmFyeShjaG9yb3BsZXRocikNCmxpYnJhcnkoY2hvcm9wbGV0aHJNYXBzKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgKipSIFNlc3Npb24gSW5mbyoqICANCg0KYGBge3J9DQpzZXNzaW9uSW5mbygpDQpgYGANCg0KIyAqKlNldHVwKioNCg0KRm9yIGZpcnN0IHRpbWUgdXNlcnMsIGJlZm9yZSBydW5uaW5nIGFueSBjaHVua3MgaW4gdGhpcyBub3RlYm9vazoNCg0KKiBJbnN0YWxsIHRoZSBgZGF0YS53b3JsZGAgUiBwYWNrYWdlOg0KICBgYGANCiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJkYXRhZG90d29ybGQvZGF0YS53b3JsZC1yIiwgYnVpbGRfdmlnbmV0dGVzID0gVFJVRSwgZm9yY2UgPSBUUlVFKQ0KICBgYGANCiogR2V0IHlvdXIgQVBJIGF1dGhlbnRpY2F0aW9uIHRva2VuIGF0IGh0dHBzOi8vZGF0YS53b3JsZC9zZXR0aW5ncy9hZHZhbmNlZA0KKiBDb25maWd1cmUgdGhlIGBkYXRhLndvcmxkYCBwYWNrYWdlOg0KICBgYGANCiAgZGF0YS53b3JsZDo6c2V0X2NvbmZpZyhkYXRhLndvcmxkOjpzYXZlX2NvbmZpZyhhdXRoX3Rva2VuID0gIllPVVIgVE9LRU4iKSkNCiAgYGBgDQoNCkNvbmZpZ3VyYXRpb24gd2lsbCBiZSBzYXZlZCBhdCBgfi8uZHcvY29uZmlnYCBhbmQgYXV0b21hdGljYWxseSBhcHBsaWVkIHRvIGFsbCBmdXR1cmUgUiBzZXNzaW9ucy4NCg0KIyAqKkNvbm5lY3RpbmcgdG8gZGF0YS53b3JsZCoqDQoNCkRlc2NyaXB0aW9uIG9mIG91ciBkYXRhc2V0OiBzZXZlbiBkaWZmZXJlbnQgdGFibGVzIGNvbnRhaW5pbmcgY2Vuc3VzIHBvcHVsYXRpb24sIGluY29tZSwgaW50ZXJuZXQgdXNhZ2UsIGFuZCBmYWNlYm9vayB1c2FnZSBpbmZvcm1hdGlvbi4NCg0KYGBge3J9DQpwcm9qZWN0IDwtICJodHRwczovL2RhdGEud29ybGQvYXBrNTg1L2YtMTctZWR2LXByb2plY3QtNSINCmRhdGEud29ybGQ6OnNldF9jb25maWcoY2ZnX2VudigiRFdfQVBJIikpDQoNCmBgYA0KIyAqKlRhYmxlYXUgV29ya2Jvb2sgTGlua3MqKg0KDQpUYWJsZWF1IFdvcmtib29rcyBVdGlsaXplZDogDQpodHRwczovL3B1YmxpYy50YWJsZWF1LmNvbS9wcm9maWxlL2phbWVzLmxpbjc5ODcjIS92aXpob21lL1Byb2plY3Q1VGFibGVhdS1KYW1lc0xpbi9CYXJjaGFydDE/cHVibGlzaD15ZXMNCg0KIyAqKklucHV0dGluZyBhbmQgQ2xlYW5pbmcgdGhlIENTVnMqKg0KRm9yIHRoaXMgcHJvamVjdCwgd2UgZGVjaWRlZCB0byB1c2UgZGF0YSBmcm9tIDcgZGlmZmVyZW50IGRhdGEgc2V0cy4gVGhlIGRhdGEgc2V0cyBjb250YWluZWQgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjoNCiAgMSkgMjAwNyBJbnRlcm5ldCBVc2FnZSBEYXRhDQogIDIpIDIwMTIgSW50ZXJuZXQgVXNhZ2UgRGF0YQ0KICAzKSAyMDA3IFBvcHVsYXRpb24gYnkgQWdlIEdyb3VwDQogIDQpIDIwMTIgUG9wdWxhdGlvbiBieSBBZ2UgR3JvdXANCiAgNSkgMjAwNyBNZWFuIEluY29tZSBieSBTdGF0ZQ0KICA2KSAyMDEyIE1lYW4gSW5jb21lIGJ5IFN0YXRlDQogIDcpIEZhY2Vib29rIFVzYWdlIERhdGEgKGFwcHJveC4gMjAxMCkNCiAgDQpXZSBkZWNpZGVkIHRvIHJlYWQgdGhlc2UgQ1NWcyBvbmUgYnkgb25lIGFuZCBjaGVjayB3aGV0aGVyIG9yIG5vdCBSIHdvdWxkIGludGVycHJldCB0aGUgY29sdW1uIHR5cGVzIGNvcnJlY3RseS4gV2UgZm91bmQgdGhhdCBSIHJlYWQgaW4gYWxsIHRoZSBjb2x1bW4gdHlwZXMgY29ycmVjdGx5IGZvciBhbGwgb2YgdGhlIGRhdGEgc2V0cyBleGNlcHQgZm9yIHRocmVlIGRhdGEgc2V0czogMjAxMk1lYW5JbmNvbWVEYXRhLCAyMDA3TWVhbkluY29tZURhdGEsIGFuZCBGYWNlYm9va0RhdGEuIFRoZSBtZWFuIGluY29tZSBkYXRhIHNldHMgY29udGFpbmVkIGRvbGxhciBzaWducyBhbmQgdGh1cywgUiB3YXMgaW50ZXJwcmV0aW5nIHRoZXNlIGNvbHVtbnMgYXMgY2hhcmFjdGVycy4gT24gdGhlIG90aGVyIGhhbmQsIEZhY2Vib29rJ3MgZGF0YSBzZXQgY29udGFpbmVkIHBlcmNlbnRhZ2VzLCB3aGljaCBhbHNvIGNhdXNlZCBSIHRvIGludGVycGV0IHRoZXNlIGNvbHVtbnMgYXMgY2hhcmFjdGVycy4gVGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdHMgYmVsb3cuDQoNCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vMjRWOWozay5wbmcpDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS80N1RuUWFHLnBuZykNCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vOWo4Z3JKTC5wbmcpDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9GRXNscFd1LnBuZykNCg0KVGhpcyB3YXMgdGhlIHJlc3VsdCBvZiB1c2luZyByZWFkX2NzdiB3aXRob3V0IHNwZWNpZnlpbmcgdGhlIGNvcnJlY3QgY29sdW1uIHR5cGVzIGZvciB0aGUgbWVhbiBpbmNvbWUgZGF0YSBzZXRzLiBBcyBjYW4gYmUgc2VlbiwgUiBpbnRlcnByZXRlZCBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgYXMgYSBjaGFyYWN0ZXIgZHVlIHRvIHRoZSBkb2xsYXIgc2lnbnMgY29udGFpbmVkIGluIHRoZSBkYXRhIHNldC4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vVWpvandvcC5wbmcpDQoNClRoaXMgd2FzIHRoZSByZXN1bHQgb2YgdXNpbmcgcmVhZF9jc3Ygd2l0aG91dCBzcGVjaWZ5aW5nIHRoZSBjb3JyZWN0IGNvbHVtbiB0eXBlcyBmb3IgdGhlIGZhY2Vib29rIGRhdGEgc2V0LiBBcyBjYW4gYmUgc2VlbiwgUiBpbmNvcnJlY3RseSBpbnRlcnByZXRlZCBGYWNlYm9vayBQZW5ldHJhdGlvbiwgSW50ZXJuZXQgUGVuZXRyYXRpb24sIGFuZCBQb3B1bGF0aW9uIFBlcmNlbnQgb2YgVVNBIGFzIGNoYXJhY3RlciBjb2x1bW5zLg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS8ybzU3YUtDLnBuZykNCg0KVGhlIHJlc3Qgb2YgdGhlIGNvbHVtbnMgaW4gdGhlIG90aGVyIDUgZGF0YSBzZXRzIGhvd2V2ZXIgd2VyZSBwYXJzZWQgY29ycmVjdGx5IGFzIHNob3duIGluIHRoZSBzY3JlZW4gc2hvdCBhYm92ZS4NCg0KDQpJbiBvcmRlciB0byBmaXggdGhlIHByb2JsZW0gd2UgcmFuIGludG8gZm9yIG91ciBvdGhlciAzIGRhdGEgc2V0cywgd2UgbWFudWFsbHkgc3BlY2lmaWVkIHRoZSBjb2x1bW4gdHlwZXMgYXMgY29sX251bWJlcigpIGFzIHNob3duIGluIHRoZSBzY3JlZW5zaG90IG9mIHRoZSBjb2RlIGJlbG93LiBUaGUgZGF0YSBzZXRzIGhhdmUgbm93IGFsbCBiZWVuIGNsZWFuZWQgZm9yIGNvbHVtbiB0eXBlcy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vMTdKRWM4TC5wbmcpDQoNCg0KDQpgYGB7cn0NCg0KI1JlYWRpbmcgaW4gMjAwNyBQb3B1bGF0aW9uIERhdGENCnBvcHVsYXRpb25fMjAwNyA9IHJlYWRfY3N2KCJodHRwczovL3F1ZXJ5LmRhdGEud29ybGQvcy9jczhVdm9DZk9rcnNSZ2FpLVJjSXhldERVcXFCOUkiKQ0KDQojUmVhZGluZyBpbiAyMDEyIFBvcHVsYXRpb24gRGF0YQ0KcG9wdWxhdGlvbl8yMDEyID0gcmVhZF9jc3YoImh0dHBzOi8vcXVlcnkuZGF0YS53b3JsZC9zL3ZXSlBENHZ6VFFaSjdxSXVpTWpwVnYxWDBTMEFJcSIpDQoNCiNSZWFkaW5nIGluIDIwMDcgSW50ZXJuZXQgQWNjZXNzIERhdGENCmludGVybmV0XzIwMDcgPSByZWFkX2NzdigiaHR0cHM6Ly9xdWVyeS5kYXRhLndvcmxkL3MvUjFjT3dvQkNCYTRjSFdtZWVvaDJZdjZ6M2daMzdQIikNCg0KI1JlYWRpbmcgaW4gMjAxMiBJbnRlcm5ldCBBY2Nlc3MgRGF0YQ0KaW50ZXJuZXRfMjAxMiA9IHJlYWRfY3N2KCJodHRwczovL3F1ZXJ5LmRhdGEud29ybGQvcy9xMmFSUllJMm5iNkpmajVaRjdiNmM2M1Q0TWNhY3oiKQ0KDQojUmVhZGluZyBpbiAyMDA3IE1lYW4gSW5jb21lIERhdGEgLSBpbmNvcnJlY3QgY29sdW1uIHBhcnNpbmcgYnkgUg0KICAgICMjIHJlYWRfY3N2KCJodHRwczovL3F1ZXJ5LmRhdGEud29ybGQvcy80bUJRVHoyNGU4bG9TV29VVjItb2lDSnFIQUNSVzQiKQ0KDQoNCiAgICAjIENvcnJlY3RlZCBjb2x1bW4gcGFyc2luZw0KICAgICAgaW5jb21lXzIwMDcgPSByZWFkX2NzdigiaHR0cHM6Ly9xdWVyeS5kYXRhLndvcmxkL3MvNG1CUVR6MjRlOGxvU1dvVVYyLW9pQ0pxSEFDUlc0IiwNCiAgICAgICAgICAgIGNvbF90eXBlcyA9IGxpc3QoDQogICAgICAgICAgICBSZWdpb24gPSBjb2xfY2hhcmFjdGVyKCksDQogICAgICAgICAgICBgQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lYCA9IGNvbF9udW1iZXIoKQ0KICAgICAgKQ0KICAgICAgKQ0KDQojUmVhZGluZyBpbiAyMDEyIE1lYW4gSW5jb21lIERhdGEgLSBpbmNvcnJlY3QgY29sdW1uIHBhcnNpbmcgYnkgUg0KICAgICMjIHJlYWRfY3N2KCJodHRwczovL3F1ZXJ5LmRhdGEud29ybGQvcy9LOE9HbER5YTR2ekVqWHNranZuS0xjeFMyb0RqNUEiKQ0KICAgICAgDQogICAgDQogICAgIyBDb3JyZWN0ZWQgY29sdW1uIHBhcnNpbmcNCiAgICAgIGluY29tZV8yMDEyID0gcmVhZF9jc3YoImh0dHBzOi8vcXVlcnkuZGF0YS53b3JsZC9zL0s4T0dsRHlhNHZ6RWpYc2tqdm5LTGN4UzJvRGo1QSIsDQogICAgICAgICAgICBjb2xfdHlwZXMgPSBsaXN0KA0KICAgICAgICAgICAgUmVnaW9uID0gY29sX2NoYXJhY3RlcigpLA0KICAgICAgICAgICAgYEF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZWAgPSBjb2xfbnVtYmVyKCkNCiAgICAgICkNCiAgICAgICkNCg0KICAgICAgDQojUmVhZGluZyBpbiB0aGUgRmFjZWJvb2sgQ1NWDQogICAgIyMgZmFjZWJvb2sgPSByZWFkX2NzdigiaHR0cHM6Ly9xdWVyeS5kYXRhLndvcmxkL3MvVkxLQ284Tmp1bnB6WHlNT1hOd0ZIRUJPQVR0QnZ6IikNCiAgICAgIA0KICAgICMgQ29ycmVjdGVkIGNvbHVtbiBwYXJzaW5nDQogICAgICBmYWNlYm9vayA9IHJlYWRfY3N2KCJodHRwczovL3F1ZXJ5LmRhdGEud29ybGQvcy9WTEtDbzhOanVucHpYeU1PWE53RkhFQk9BVHRCdnoiLA0KICAgICAgICAgICAgY29sX3R5cGVzID0gbGlzdCgNCiAgICAgICAgICAgIFJlZ2lvbiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICAgICAgICAgIGBQb3B1bGF0aW9uIFBlcmNlbnQgb2YgVVNBYCA9IGNvbF9udW1iZXIoKSwNCiAgICAgICAgICAgIGBJbnRlcm5ldCBQZW5ldHJhdGlvbmAgPSBjb2xfbnVtYmVyKCksDQogICAgICAgICAgICBgRmFjZW9vayBVc2Vyc2AgPSBjb2xfbnVtYmVyKCksDQogICAgICAgICAgICBgRmFjZWJvb2sgUGVuZXRyYXRpb25gID0gY29sX251bWJlcigpDQopDQopDQoNCg0KYGBgDQoNCldlIHRoZW4gdXNlZCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBpbiBvcmRlciB0byByaWQgb3VyIGRhdGFzZXRzIG9mIGFueSBub24gcHJpbnRhYmxlIGNoYXJhY3RlcnMuIFRoZSBjb2RlIHVzZWQgZm9yIHRoaXMgaXMgc2hvd24gaW4gdGhlIHNjcmVlbnNob3QgYmVsb3cuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL1ZsRWxDT1AucG5nKQ0KDQoNCmBgYHtyfQ0KDQpmb3IgKG4gaW4gbmFtZXMoZmFjZWJvb2spKSB7DQoJZmFjZWJvb2tbbl0gPC0gZGF0YS5mcmFtZShsYXBwbHkoZmFjZWJvb2tbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMocG9wdWxhdGlvbl8yMDA3KSkgew0KCXBvcHVsYXRpb25fMjAwN1tuXSA8LSBkYXRhLmZyYW1lKGxhcHBseShwb3B1bGF0aW9uXzIwMDdbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMocG9wdWxhdGlvbl8yMDEyKSkgew0KCXBvcHVsYXRpb25fMjAxMltuXSA8LSBkYXRhLmZyYW1lKGxhcHBseShwb3B1bGF0aW9uXzIwMTJbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMoaW50ZXJuZXRfMjAwNykpIHsNCglpbnRlcm5ldF8yMDA3W25dIDwtIGRhdGEuZnJhbWUobGFwcGx5KGludGVybmV0XzIwMDdbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMoaW50ZXJuZXRfMjAxMikpIHsNCglpbnRlcm5ldF8yMDEyW25dIDwtIGRhdGEuZnJhbWUobGFwcGx5KGludGVybmV0XzIwMTJbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMoaW5jb21lXzIwMDcpKSB7DQoJaW5jb21lXzIwMDdbbl0gPC0gZGF0YS5mcmFtZShsYXBwbHkoaW5jb21lXzIwMDdbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQpmb3IgKG4gaW4gbmFtZXMoaW5jb21lXzIwMTIpKSB7DQoJaW5jb21lXzIwMTJbbl0gPC0gZGF0YS5mcmFtZShsYXBwbHkoaW5jb21lXzIwMTJbbl0sIGdzdWIsIHBhdHRlcm49IlteIC1+XSIscmVwbGFjZW1lbnQ9IiIpKQ0KfQ0KDQoNCmBgYA0KDQoNCiMgKipFeHBvcnRpbmcgdGhlIENTVnMgYW5kIExvYWRpbmcgaW50byBkYXRhLndvcmxkKioNCg0KVGhlIG5leHQgc3RlcCBpbiB0aGUgZGF0YSBzY2llbmNlIHBpcGVsaW5lIHdhcyB0byBleHBvcnQgdGhlIENTVnMgYW5kIHVwbG9hZCB0aGVtIHRvIGRhdGEud29ybGQuIFRoZSBmb2xsb3dpbmcgZGlzcGxheXMgY29kZSB1dGlsaXppZWQgdG8gZG8gdGhhdC4gV2UgYXJlIG5vdyByZWFkeSB0byBidWlsZCBvdXIgZGF0YSBtb2RlbC4NCg0KYGBge3J9DQojIyBVc2VkIHRvIGV4cG9ydCB0aGUgY2xlYW5lZCBDU1ZzDQoNCg0KI3dyaXRlX2NzdihmYWNlYm9vaywgIkM6L1VzZXJzL0phbWVzIExpbi9Eb2N1bWVudHMvUERGLERPQyxQUFQvMjAxNyBGYWxsL0NTIDMyOUUvUHJvamVjdCAjNS9GYWNlYm9va19DbGVhbmVkLmNzdiIpDQoNCiN3cml0ZV9jc3YocG9wdWxhdGlvbl8yMDA3LCAiQzovVXNlcnMvSmFtZXMgTGluL0RvY3VtZW50cy9QREYsRE9DLFBQVC8yMDE3IEZhbGwvQ1MgMzI5RS9Qcm9qZWN0ICM1LzIwMDdQb3B1bGF0aW9uX0NsZWFuZWQuY3N2IikNCg0KI3dyaXRlX2Nzdihwb3B1bGF0aW9uXzIwMTIsICJDOi9Vc2Vycy9KYW1lcyBMaW4vRG9jdW1lbnRzL1BERixET0MsUFBULzIwMTcgRmFsbC9DUyAzMjlFL1Byb2plY3QgIzUvMjAxMlBvcHVsYXRpb25fQ2xlYW5lZC5jc3YiKQ0KDQojd3JpdGVfY3N2KGludGVybmV0XzIwMDcsICJDOi9Vc2Vycy9KYW1lcyBMaW4vRG9jdW1lbnRzL1BERixET0MsUFBULzIwMTcgRmFsbC9DUyAzMjlFL1Byb2plY3QgIzUvMjAwN0ludGVybmV0X0NsZWFuZWQuY3N2IikNCg0KI3dyaXRlX2NzdihpbnRlcm5ldF8yMDEyLCAiQzovVXNlcnMvSmFtZXMgTGluL0RvY3VtZW50cy9QREYsRE9DLFBQVC8yMDE3IEZhbGwvQ1MgMzI5RS9Qcm9qZWN0ICM1LzIwMTJJbnRlcm5ldF9DbGVhbmVkLmNzdiIpDQoNCiN3cml0ZV9jc3YoaW5jb21lXzIwMDcsICJDOi9Vc2Vycy9KYW1lcyBMaW4vRG9jdW1lbnRzL1BERixET0MsUFBULzIwMTcgRmFsbC9DUyAzMjlFL1Byb2plY3QgIzUvMjAwN0luY29tZV9DbGVhbmVkLmNzdiIpDQoNCiN3cml0ZV9jc3YoaW5jb21lXzIwMTIsICJDOi9Vc2Vycy9KYW1lcyBMaW4vRG9jdW1lbnRzL1BERixET0MsUFBULzIwMTcgRmFsbC9DUyAzMjlFL1Byb2plY3QgIzUvMjAxMkluY29tZV9DbGVhbmVkLmNzdiIpDQoNCmBgYA0KDQojICoqQnVpbGRpbmcgdGhlIERhdGEgTW9kZWwqKg0KDQpOb3cgdGhhdCB3ZSBoYXZlIGNsZWFuZWQsIGV4cG9ydGVkLCBhbmQgdXBsb2FkZWQgb3VyIGRhdGEgb250byBkYXRhLndvcmxkLCB3ZSBhcmUgcmVhZHkgdG8gYnVpbGQgb3VyIGRhdGEgbW9kZWwuIFRoZSBmb2xsb3dpbmcgc2NyZWVuc2hvdCByZWZsZWN0cyB0aGUgcmVsYXRpb25zaGlwcyBvZiBvdXIgZmluYWwgc2V0IG9mIGRhdGEuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL1RXTmJKZVoucG5nKQ0KDQoqKiAgICoqDQojICoqSW50ZXJlc3RpbmcgRmluZGluZ3MqKg0KDQoqKiAgICoqDQojIyAqKlJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1pbGxlbm5pYWwgUG9wdWxhdGlvbiBhbmQgSW50ZXJuZXQgQWNjZXNzKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpJbiB0aGlzIHN0ZXAsIEkgdXNlZCB0aGUgZGF0YS53b3JsZCBub24tc2VsZWN0ICogU1FMIHRvIGNyZWF0ZSB0d28gdGliYmxlcyBjb250YWluaW5nIGNvbHVtbnMgZnJvbSBmb3VyIGRpZmZlcmVudCBkYXRhIHNvdXJjZXM6IDIwMDcgaW50ZXJuZXQgYWNjZXNzLCAyMDEyIGludGVybmV0IGFjY2VzcywgMjAwNyBwb3B1bGF0aW9uLCBhbmQgMjAxMiBwb3B1bGF0aW9uLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vWU81bkVHci5wbmcpDQoNCmBgYHtyfQ0KDQpkZl8xIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDA3SW50ZXJuZXRfQ2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyAyMDA3SUFIb21lLCBgMjAwN0ludGVybmV0X0NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZSwgYDIwMDdwb3B1bGF0aW9uX2NsZWFuZWRgLnRvdGFsX2VzdGltYXRlX3RvdGFsX3BvcHVsYXRpb25fYWdlXzE1X3RvXzE5X3llYXJzIGFzIDIwMDdfMTVfMTlQb3B1bGF0aW9uDQpGUk9NIDIwMDdJbnRlcm5ldF9DbGVhbmVkIA0KSk9JTiAyMDA3UG9wdWxhdGlvbl9jbGVhbmVkIE9OIGAyMDA3SW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uICA9IGAyMDA3UG9wdWxhdGlvbl9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQoNCmRmXzIgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KKCJTRUxFQ1QgYDIwMTJJbnRlcm5ldF9DbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIEFTIDIwMTJJQUhvbWUsIGAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLCBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfZXN0aW1hdGVfYWdlXzE1X3RvXzE5X3llYXJzIGFzIDIwMTJfMTVfMTlQb3B1bGF0aW9uDQpGUk9NIDIwMTJJbnRlcm5ldF9DbGVhbmVkIA0KSk9JTiAyMDEyUG9wdWxhdGlvbl9jbGVhbmVkIE9OIGAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uICA9IGAyMDEyUG9wdWxhdGlvbl9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KQXMgY2FuIGJlIHNlZW4gaW4gdGhlIGZvdXIgZ3JhcGhzIGJlbG93LCBpdCBzZWVtcyB0aGF0IHRoZSBwZXJjZW50YWdlIG9mIHRoZSBtaWxsZW5uaWFsIHBvcHVsYXRpb24gd2l0aCByZXNwZWN0IHRvIGEgc3RhdGUgaXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgcGVyY2VudGFnZSBvZiBpbmRpdmlkdWFscyB3aG8gYWNjZXNzIHRoZSBpbnRlcm5ldCBmcm9tIGhvbWUgYnkgc3RhdGUgaW4gMjAwNy4gSG93ZXZlciwgdGhpcyByZWxhdGlvbnNoaXAgZG9lcyBub3Qgc2VlbSB0byBob2xkIGFzIHN0cm9uZ2x5IGluIDIwMTIuIEluIDIwMDcsIGl0IGlzIGNsZWFyIHRoYXQgdGhlcmUgaXMgZGlzY2VybmlibGUgcmVsYXRpb25zaGlwIGFzIG1hbnkgc3RhdGVzIHRoYXQgYXJlIGFib3ZlIHRoZSB0YWJsZSBhdmVyYWdlIGZvciBvbmUgZ3JhcGggYXJlIGFib3ZlIHRoZSB0YWJsZSBhdmVyYWdlIGZvciB0aGUgc2Vjb25kIGdyYXBoLiBGb3IgMjAxMiwgdGhpcyBkb2VzIG5vdCBuZWNlc3NhcmlseSBzZWVtIHRvIGJlIHRoZSBjYXNlLg0KDQpUaGVyZSBjb3VsZCBiZSBudW1lcm91cyBleHBsYW5hdGlvbnMgZm9yIHRoaXMuIEkgYmVsaWV2ZSBvbmUgcG9zc2libGUgZXhwbGFuYXRpb24gaXMgYXMgcHVibGljIGZhY2lsaXRpZXMgc3VjaCBhcyBzY2hvb2xzIHN0YXJ0ZWQgdG8gYWRhcHQgaGlnaCBzcGVlZCBpbnRlcm5ldCBhbmQgdXNlIGl0LCBsZXNzIGFuZCBsZXNzIG1pbGxlbm5pYWxzIHdvdWxkIGFjY2VzcyBpdCBmcm9tIGhvbWUgYW5kIG1vcmUgYW5kIG1vcmUgd291bGQgc3RhcnQgdG8gYWNjZXNzIGl0IGZyb20gcHVibGljIGZhY2lsaXRpZXMuIEhvd2V2ZXIsIHRoaXMgcmVsYXRpb25zaGlwIG1heSBub3QgaG9sZCB0cnVlIGdvaW5nIHBhc3QgMjAxMiBhcyBpbnRlcm5ldCBhcyB3ZWxsIGFzIGRldmljZXMgdXNlZCB0byBhY2Nlc3MgdGhlIGludGVybmV0IGJlY29tZSBtb3JlIHdpZGVzcHJlYWQgYW5kIGNoZWFwZXIuDQoNCmBgYHtyfQ0KDQpNZWFuczIwMDcgPC0gZGZfMSAlPiUgZHBseXI6OnN1bW1hcml6ZShQb3B1bGF0aW9uXzE1dG8xOV8yMDA3TWVhbiA9IG1lYW4oYDIwMDdfMTVfMTlQb3B1bGF0aW9uYCksIEludGVybmV0QWNlc3NfQXRIb21lXzIwMDdNZWFuID0gbWVhbihgMjAwN0lBSG9tZWApKQ0KcmVuZGVyRGF0YVRhYmxlKHsNCiAgRFQ6OmRhdGF0YWJsZShNZWFuczIwMDcsIHJvd25hbWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9IGxpc3QoUmVzcG9uc2l2ZSA9IFRSVUUsIEZpeGVkSGVhZGVyID0gVFJVRSkNCiAgKQ0KfSkNCg0KaW5wdXRQYW5lbCgNCiAgc2VsZWN0SW5wdXQoInNlbGVjdFJlZ2lvbmRmXzEiLCBsYWJlbCA9ICJTZWxlY3QgUmVnaW9uIiwNCiAgICAgICAgICAgICAgY2hvaWNlcyA9IGRmXzEkU3RhdGUsIG11bHRpcGxlPVRSVUUsIHNlbGVjdGVkPWRmXzEkU3RhdGUpDQopDQoNCnJlbmRlclBsb3Qoe2RmXzEgJT4lIGRwbHlyOjpzZWxlY3QoU3RhdGUsYDIwMDdfMTVfMTlQb3B1bGF0aW9uYCkgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGZfMSkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PSBgMjAwN18xNV8xOVBvcHVsYXRpb25gKSwgc3RhdD0iaWRlbnRpdHkiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD03LjI2MTUzODQ2MTUzODQ2LCBjb2xvciA9ICJibHVlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiTWlsbGVubmlhbCBQb3B1bGF0aW9uIGJ5IFN0YXRlICgyMDA3KSIsIHg9IlN0YXRlIiwgeT0iUG9wdWxhdGlvbiBQZXJjZW50YWdlIil9KQ0KDQpyZW5kZXJQbG90KHtkZl8xICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlLGAyMDA3SUFIb21lYCkgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGZfMSkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PSBgMjAwN0lBSG9tZWApLCBzdGF0PSJpZGVudGl0eSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTY3LjQxMzQ2MTUzODQ2MTUsIGNvbG9yID0gImJsdWUiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEluY29tZSBieSBTdGF0ZSAoMjAwNykiLCB4PSJTdGF0ZSIsIHk9IkF2ZXJhZ2UgSW5jb21lIil9KQ0KDQoNCg0KDQpNZWFuczIwMTIgPC0gZGZfMiAlPiUgZHBseXI6OnN1bW1hcml6ZShQb3B1bGF0aW9uXzE1dG8xOV8yMDEyTWVhbj0gbWVhbihgMjAxMl8xNV8xOVBvcHVsYXRpb25gKSwgSW50ZXJuZXRBY2Vzc19BdEhvbWVfMjAxMk1lYW4gPSBtZWFuKGAyMDEySUFIb21lYCkpDQpyZW5kZXJEYXRhVGFibGUoew0KICBEVDo6ZGF0YXRhYmxlKE1lYW5zMjAxMiwgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICBleHRlbnNpb25zID0gbGlzdChSZXNwb25zaXZlID0gVFJVRSwgRml4ZWRIZWFkZXIgPSBUUlVFKQ0KICApDQp9KQ0KDQppbnB1dFBhbmVsKA0KICBzZWxlY3RJbnB1dCgic2VsZWN0UmVnaW9uZGZfMiIsIGxhYmVsID0gIlNlbGVjdCBSZWdpb24iLA0KICAgICAgICAgICAgICBjaG9pY2VzID0gZGZfMiRTdGF0ZSwgbXVsdGlwbGU9VFJVRSwgc2VsZWN0ZWQ9ZGZfMiRTdGF0ZSkNCikNCg0KcmVuZGVyUGxvdCh7ZGZfMiAlPiUgZHBseXI6OnNlbGVjdChTdGF0ZSxgMjAxMl8xNV8xOVBvcHVsYXRpb25gKSAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSA9PSBpbnB1dCRzZWxlY3RSZWdpb25kZl8yKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHg9U3RhdGUsIHk9IGAyMDEyXzE1XzE5UG9wdWxhdGlvbmApLCBzdGF0PSJpZGVudGl0eSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNi44MjMwNzY5MjMwNzY5MiwgY29sb3IgPSAiYmx1ZSIpKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsgbGFicyh0aXRsZSA9ICJNaWxsZW5uaWFsIFBvcHVsYXRpb24gYnkgU3RhdGUgKDIwMTIpIiwgeD0iU3RhdGUiLCB5PSJQb3B1bGF0aW9uIFBlcmNlbnRhZ2UiKX0pDQoNCg0KcmVuZGVyUGxvdCh7ZGZfMiAlPiUgZHBseXI6OnNlbGVjdChTdGF0ZSxgMjAxMklBSG9tZWApICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlID09IGlucHV0JHNlbGVjdFJlZ2lvbmRmXzIpICU+JSBnZ3Bsb3QoKSArIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT0gYDIwMTJJQUhvbWVgKSwgc3RhdD0iaWRlbnRpdHkiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDY5Ljk5MjMwNzY5MjMwNzcsIGNvbG9yID0gImJsdWUiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEluY29tZSBieSBTdGF0ZSAoMjAxMikiLCB4PSJTdGF0ZSIsIHk9IkF2ZXJhZ2UgSW5jb21lIil9KQ0KDQoNCmBgYA0KDQoqKiAgICoqDQojIyAqKlJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMioqDQoNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpGb3IgdGhpcyBpbnNpZ2h0LCBJIGRlY2lkZWQgdG8gY3JlYXRlIHR3byBkYXRhIGZyYW1lcyBjb250YWluaW5nIDIwMDcgYW5kIDIwMTIgaW5mb3JtYXRpb24gb24gaW50ZXJuZXQgYWNjZXNzIG91dHNpZGUgdGhlIGhvbWUgYXMgd2VsbCBhcyBpbmNvbWUuIFRoZSBjb2RlIGZvciB0aGlzIGlzIHNob3duIGluIHRoZSBzY3JlZW5zaG90IGJlbG93LiBCb3RoIGRhdGEgZnJhbWVzIHdpbGwgcmVxdWlyZSB0aWR5aW5nIHdoaWNoIHdpbGwgYmUgZG9uZSB0aHJvdWdoIGdhdGhlcmluZyBpbiB0aGUgc3RlcCBmb2xsb3dpbmcgdGhpcy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vUmx6NjE5eS5wbmcpDQoNCmBgYHtyfQ0KZGZfMyA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9vdXRzaWRlX29mX2hvdXNlaG9sZCBhcyAyMDA3LCBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZXMsDQpgMjAxMmludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9vdXRzaWRlX29mX2hvdXNlaG9sZCBhcyAyMDEyDQpGUk9NIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGANCkpPSU4gYDIwMTJpbnRlcm5ldF9jbGVhbmVkYCANCk9OIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uID0gYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQoNCmRmXzQgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KKCJTRUxFQ1QgYDIwMDdpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIGAyMDA3YCwgYDIwMTJpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIGAyMDEyYCwgYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlcw0KRlJPTSAyMDA3aW5jb21lX2NsZWFuZWQgSk9JTiAyMDEyaW5jb21lX2NsZWFuZWQgT04gYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uID0gYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpUaGUgbmV4dCBzdGVwIGluIHRoZSBkYXRhIHNjaWVuY2UgcGlwZWxpbmUgaXMgdG8gZ2F0aGVyIHRoZSBjb2x1bW5zIGludG8gYSBzZXQgb2Yga2V5IHZhbHVlIHBhaXJzLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBiZWxvdy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vMjJzd1hNQy5wbmcpDQoNCmBgYHtyfQ0KDQpkZl8zIDwtIGRmXzMgJT4ldGlkeXI6OmdhdGhlcigiWWVhciIsICJQZXJjZW50YWdlIiwJLTIpDQpkZl80IDwtIGRmXzQgJT4ldGlkeXI6OmdhdGhlcigiWWVhciIsICJJbmNvbWUiLAktMykNCg0KDQpgYGANCg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KRm9yIHRoaXMgaW5zaWdodCwgSSBkZWNpZGVkIHRvIHVzZSBkYXRhIGZyb20gNCB0YWJsZXM6IDIwMDdJbmNvbWUsIDIwMTJJbmNvbWUsIDIwMDdJbnRlcm5ldFVzYWdlLCAyMDEySW50ZXJuZXRVc2FnZS4NCg0KSW5pdGlhbGx5LCBJIHdhcyBjdXJpb3VzIHRvIHNlZSB3aGF0IHRoZSBjaGFuZ2UgaW4gaW50ZXJuZXQgYWNjZXNzIG91dHNpZGUgb2YgdGhlIGhvdXNlaG9sZCB3b3VsZCBiZSBmcm9tIDIwMDcgdG8gMjAxMiBmb3IgZGlmZmVyZW50IHN0YXRlcy4gVGhlcmVmb3JlLCBJIGRlY2lkZWQgdG8gY3JlYXRlIHR3byBtYXBzIHRvIHNob3cgdGhpcyBjaGFuZ2U6IG9uZSBmb3IgMjAwNyBhbmQgdGhlIG90aGVyIGZvciAyMDEyLiBUaGUgbWFwcyBhcmUgc2hvd24gYmVsb3cuIEFzIGNhbiBiZSBzZWVuLCBpbiBjcmVhdGluZyB0aGUgbWFwcywgSSB1c2VkIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbHRlciBvdXQgaW5mb3JtYXRpb24gdW5pcXVlIHRvIDIwMDcgYW5kIDIwMTIuDQoNCiFbVGhlIGFib3ZlIHJlZ3VsYXIgZXhwcmVzc2lvbiBmaWx0ZXJzIG91dCBhbGwgcm93cyB0aGF0IHN0YXJ0IHdpdGggYW55IGNoYXJhY3RlciwgYnV0IGVuZCB3aXRoIDEyXShodHRwczovL2kuaW1ndXIuY29tLzZ5alJobjAucG5nKQ0KDQohW1RoZSBhYm92ZSByZWd1bGFyIGV4cHJlc3Npb24gZmlsdGVycyBvdXQgYWxsIHJvd3MgdGhhdCBzdGFydCB3aXRoIGFueSBjaGFyYWN0ZXIsIGJ1dCBlbmQgd2l0aCAwN10oaHR0cHM6Ly9pLmltZ3VyLmNvbS96Q2JUMDE4LnBuZykNCg0KDQpgYGB7cn0NCmRmXzIwMDcgPC0gZGZfMyAlPiUgZHBseXI6OmZpbHRlcighZ3JlcGwoIi4qMTIkIiwgWWVhcikpICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlcywgUGVyY2VudGFnZSkNCg0KbmFtZXMoZGZfMjAwNykgPC0gYygicmVnaW9uIiwgInZhbHVlIikNCmRmXzIwMDckcmVnaW9uIDwtIHRvbG93ZXIoZGZfMjAwNyRyZWdpb24pDQpkZl8yMDA3JHJlZ2lvbiA8LSBnc3ViKCIgKHUucy4gc3RhdGUpIiwgIiIsIGRmXzIwMDckcmVnaW9uLCBmaXhlZD1UUlVFKQ0KcmVuZGVyUGxvdCh7c3RhdGVfY2hvcm9wbGV0aChkZl8yMDA3KSArIGxhYnModGl0bGUgPSAiSW50ZXJuZXQgVXNhZ2UgT3V0c2lkZSBIb3VzZWhvbGQgKDIwMDcpIil9KQ0KDQoNCmRmXzIwMTMgPC0gZGZfMyAlPiUgZHBseXI6OmZpbHRlcighZ3JlcGwoIi4qMDckIiwgWWVhcikpICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlcywgUGVyY2VudGFnZSkNCg0KbmFtZXMoZGZfMjAxMykgPC0gYygicmVnaW9uIiwgInZhbHVlIikNCmRmXzIwMTMkcmVnaW9uIDwtIHRvbG93ZXIoZGZfMjAxMyRyZWdpb24pDQpkZl8yMDEzJHJlZ2lvbiA8LSBnc3ViKCIgKHUucy4gc3RhdGUpIiwgIiIsIGRmXzIwMTMkcmVnaW9uLCBmaXhlZD1UUlVFKQ0KcmVuZGVyUGxvdCh7c3RhdGVfY2hvcm9wbGV0aChkZl8yMDEzKSArIGxhYnModGl0bGUgPSAiSW50ZXJuZXQgVXNhZ2UgT3V0c2lkZSBIb3VzZWhvbGQgKDIwMTIpIil9KQ0KDQpgYGANCg0KQXMgY2FuIGJlIHNlZW4sIGl0IHNlZW1zIHRoYXQgbW9zdCBvZiB0aGUgc3RhdGVzIGhhZCByZWxhdGl2ZWx5IHRoZSBzYW1lIGFtb3VudCBvZiBpbnRlcm5ldCB1c2FnZSBmcm9tIDIwMDcgdG8gMjAxMiBvdXRzaWRlIHRoZSBob3VzZWhvbGQuIEhvd2V2ZXIsIGEgZmV3IHN0YXRlcyBzdHJ1Y2sgbWUgYXMgaGF2aW5nIGEgc2lnbmlmaWNhbnQgcG9zaXRpdmUgY2hhbmdlLiBUaGVzZSBzdGF0ZXMgaW5jbHVkZSBJZGFobyBhbmQgRmxvcmlkYS4NCg0KSSBkZWNpZGVkIHRvIHRha2UgYSBsb29rIGludG8gdGhpcyBmdXJ0aGVyIHRvIHNlZSBpZiB0aGVyZSB3YXMgYW55IHJlbGF0aW9uc2hpcCB3aXRoIGNoYW5nZSBpbiBhdmVyYWdlIGluY29tZSBmcm9tIDIwMDcgdG8gMjAxMi4gVGhlIG5leHQgcGxvdCBzaG93cyB0aGF0IGFsdGhvdWdoIG1vc3Qgc3RhdGVzIGV4cGVyaWVuY2VkIGEgY2hhbmdlIGluIHRoZWlyIGF2ZXJhZ2UgaW5jb21lLCByZWxhdGl2ZSB0byBvbmUgYW5vdGhlciwgdGhleSBzdGF5ZWQgcmVsYXRpdmVseSB0aGUgc2FtZS4NCg0KYGBge3J9DQoNCmRmXzIwMDdJbmNvbWUgPC0gZGZfNCAlPiUgZHBseXI6OmZpbHRlcighZ3JlcGwoIi4qMTIkIiwgWWVhcikpICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlcywgSW5jb21lKQ0KZGZfMjAwN0luY29tZTwtIGRmXzIwMDdJbmNvbWUgJT4lIGRwbHlyOjphcnJhbmdlKEluY29tZSkgDQpkZl8yMDA3SW5jb21lJFN0YXRlcyA8LSBmYWN0b3IoZGZfMjAwN0luY29tZSRTdGF0ZXMsIGxldmVscz1kZl8yMDA3SW5jb21lJFN0YXRlcykNCg0KcmVuZGVyUGxvdCh7ZGZfMjAwN0luY29tZSAlPiVnZ3Bsb3QobWFwcGluZz1hZXMoeD1TdGF0ZXMsIHk9SW5jb21lKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEluY29tZSBieSBTdGF0ZSAoMjAwNyBBcnJhbmdlZCkiLCB4PSJTdGF0ZSIsIHk9IkF2ZXJhZ2UgSW5jb21lIil9KQ0KDQoNCg0KZGZfMjAxMkluY29tZSA8LSBkZl80ICU+JSBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiLiowNyQiLCBZZWFyKSkgJT4lIGRwbHlyOjpzZWxlY3QoU3RhdGVzLCBJbmNvbWUpDQpkZl8yMDEySW5jb21lPC0gZGZfMjAxMkluY29tZSAlPiUgZHBseXI6OmFycmFuZ2UoSW5jb21lKSANCmRmXzIwMTJJbmNvbWUkU3RhdGVzIDwtIGZhY3RvcihkZl8yMDEySW5jb21lJFN0YXRlcywgbGV2ZWxzPWRmXzIwMTJJbmNvbWUkU3RhdGVzKQ0KDQpyZW5kZXJQbG90KHtkZl8yMDEySW5jb21lICU+JWdncGxvdChtYXBwaW5nPWFlcyh4PVN0YXRlcywgeT1JbmNvbWUpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpKyBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlICgyMDEyIEFycmFuZ2VkKSIsIHg9IlN0YXRlIiwgeT0iQXZlcmFnZSBJbmNvbWUiKX0pDQoNCmBgYA0KDQpIb3dldmVyLCBpbnRlcmVzdGluZ2x5IGVub3VnaCwgc29tZSBzdGF0ZXMgYWN0dWFsbHkgaGFkIGEgZGVjcmVhc2UgaW4gdGhlaXIgYXZlcmFnZSBob3VzZWhvbGQgaW5jb21lIGZyb20gMjAwNyB0byAyMDEyLiBUaGVzZSBzdGF0ZXMgd2VyZSBjZXJ0YWlubHkgdGhlIG1pbm9yaXR5LCBhbmQgaW4gb3JkZXIgdG8gZGlzcGxheSB0aGlzIHJlbGF0aW9uc2hpcCBtb3JlIHRob3JvdWdobHksIEkgY3JlYXRlZCBhIGNyb3NzIHRhYiB1c2luZyBhIGNhbGN1bGF0ZWQgZmllbGQgYXMgd2VsbCBhcyBhIHBhcmFtZXRlci4gVGhlIGNhbGN1bGF0ZWQgZmllbGQgd2FzIHRoZSBwZXJjZW50YWdlIGluY29tZSBkaWZmZXJlbmNlIGZyb20gMjAwNyB0byAyMDEyLiBUaGUgcGFyYW1ldGVyIEkgY3JlYXRlZCBhY2NlbnR1YXRlZCB3aGV0aGVyIG9yIG5vdCB0aGVpciB3YXMgYSBuZWdhdGl2ZSBkaWZmZXJlbmNlIGluIGluY29tZSwgYSBoaWdoIGRpZmZlcmVuY2UgaW4gaW5jb21lLCBvciBhIG1lZGl1bSBkaWZmZXJlbmNlIGluIGluY29tZS4gQSBzY3JlZW5zaG90IG9mIHRoYXQgY2FsY3VsYXRpb24gaXMgc2hvd24gYmVsb3cuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tLzMyM05vRGkucG5nKQ0KDQpGcm9tIG15IGNyb3NzIHRhYiwgSSBzYXcgdGhhdCBzdGF0ZXMgdGhhdCBoYWQgYSBuZWdhdGl2ZSBjaGFuZ2UgaW4gdGhlaXIgaW5jb21lIHdlcmUgb25lcyB0aGF0IGhhZCB0aGUgbW9zdCBpbmNyZWFzZSBpbiBpbnRlcm5ldCB1c2FnZSBvdXRzaWRlIHRoZSBob3VzZWhvbGQuIFRoZXNlIHdlcmUgc3RhdGVzIHN1Y2ggYXMgSWRhaG8gYW5kIEZsb3JpZGEgd2hpY2ggY2xlYXJseSBoYXZlIGEgc2lnbmlmaWNhbnQgcG9zaXRpdmUgY2hhbmdlIGluIHRoZWlyIGludGVybmV0IHVzYWdlIG91dHNpZGUgdGhlIGhvdXNlaG9sZCBhY2NvcmRpbmcgdG8gZmlyc3QgdHdvIG1hcHMuDQoNCk15IGV4cGxhbmF0aW9uIGZvciB0aGlzIGlzIHRoYXQgbW9zdCBsaWtlbHksIHN0YXRlcyB0aGF0IGhhZCBhIGRlY3JlYXNlIGluIHRoZWlyIGF2ZXJhZ2UgaW5jb21lIGhhZCBsZXNzIHBlb3BsZSB3aG8gY291bGQgYWZmb3JkIHRvIGhhdmUgaW50ZXJuZXQgaW4gdGhlIGhvdXNlLiBUaHVzLCB0aGV5IHdlbnQgZWxzZXdoZXJlIHRvIGFjY2VzcyB0aGUgaW50ZXJuZXQuIEEgc2NyZWVuc2hvdCBvZiBteSBjcm9zcyB0YWIgaXMgc2hvd24gYmVsb3cuDQoNCg0KYGBge3J9DQppbnB1dFBhbmVsKA0KICBzZWxlY3RJbnB1dCgic2VsZWN0UmVnaW9uZGZfNCIsIGxhYmVsID0gIlNlbGVjdCBSZWdpb24iLA0KICAgICAgICAgICAgICBjaG9pY2VzID0gZGZfNCRTdGF0ZXMsIG11bHRpcGxlPVRSVUUsIHNlbGVjdGVkPSBkZl80JFN0YXRlcykNCikNCg0KZGZfNGEgPC0gZXZlbnRSZWFjdGl2ZShjKGlucHV0JHNlbGVjdFJlZ2lvbmRmXzQpLCB7IA0KICBwcm9qZWN0IDwtICJodHRwczovL2RhdGEud29ybGQvYXBrNTg1L2YtMTctZWR2LXByb2plY3QtNSIgDQogIGRhdGEud29ybGQ6OnNldF9jb25maWcoY2ZnX2VudigiRFdfQVBJIikpIA0KICBwYXJhbVF1ZXJ5IDwtIGRhdGEud29ybGQ6OnFyeV9zcWwoDQogIA0KICJ3aXRoIHExIGFzIChTRUxFQ1QgKChgMjAxMmluY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUgLSBgMjAwN2luY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUpLyBgMjAwN2luY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUpIGFzIFBlcmNlbnRJbmNvbWVEaWZmZXJlbmNlLCBgMjAwN2luY29tZV9jbGVhbmVkYC5yZWdpb24gYXMgU3RhdGVzDQpGUk9NIDIwMDdpbmNvbWVfY2xlYW5lZA0KSk9JTiAyMDEyaW5jb21lX2NsZWFuZWQgT04gYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uID0gYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uKQ0KDQpTRUxFQ1QgcTEuUGVyY2VudEluY29tZURpZmZlcmVuY2UsIHExLlN0YXRlcywNCkNBU0UNCldIRU4gcTEuUGVyY2VudEluY29tZURpZmZlcmVuY2UgPiAwLjA1IFRIRU4gJ0hpZ2hBcHByZWNpYXRpb24nDQpXSEVOIHExLlBlcmNlbnRJbmNvbWVEaWZmZXJlbmNlIDwgMC4wMCBUSEVOICdOZWdhdGl2ZUNoYW5nZScNCkVMU0UgJ01lZGl1bUFwcHJlY2lhdGlvbicNCkVORCBBUyBJbmNvbWVQYXJhbWV0ZXINCkZST00gcTENCg0KICAgIikNCiBwYXJhbVF1ZXJ5JHBhcmFtcyA8LSBjKGlucHV0JHNlbGVjdFJlZ2lvbmRmXzQpDQogZGF0YS53b3JsZDo6cXVlcnkocGFyYW1RdWVyeSwgZGF0YXNldCA9IHByb2plY3QpDQp9KSANCg0KcmVuZGVyUGxvdCh7ZGZfNGEoKSAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZXMgPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGZfNCkgJT4lIGdncGxvdCgpICsgDQogIGdlb21fdGV4dChhZXMoeD1JbmNvbWVQYXJhbWV0ZXIsIHk9U3RhdGVzLCBsYWJlbD1QZXJjZW50SW5jb21lRGlmZmVyZW5jZSksIHNpemU9NikgKw0KICBnZW9tX3RpbGUoYWVzKHg9SW5jb21lUGFyYW1ldGVyLCB5PVN0YXRlcywgZmlsbD1JbmNvbWVQYXJhbWV0ZXIpLCBhbHBoYT0wLjUwKSArDQogICAgdGhlbWUobGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjApKSArDQogICAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwNCiAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwLCBmYWNlPSJib2xkIikpICArIA0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwLCBmYWNlID0gImJvbGQiKSkgKw0KICAgIGdndGl0bGUocGFzdGUoIlBlcmNlbnQgRGlmZmVyZW5jZSBpbiBBdmVyYWdlIEluY29tZSBmcm9tIDIwMDcgdG8gMjAxMiIpKSArDQogIHhsYWIoIkluY29tZSBQYXJhbWV0ZXIiKSArIHlsYWIoIlN0YXRlcyIpDQp9LCBoZWlnaHQgPSA1MDAsIHdpZHRoID0gMTIwMCkNCg0KDQpgYGANCg0KKiogICAqKg0KIyMgKipSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIC0gMjAwNyoqDQoNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpGb3IgdGhpcyBpbnNpZ2h0LCBJIGRlY2lkZWQgdG8gdXNlIGluZm9ybWF0aW9uIGZyb20gdGhyZWUgZGlmZmVyZW50IGRhdGEgdGFibGVzOiBGYWNlYm9va1VzYWdlLCAyMDA3QXZlcmFnZUluY29tZSwgYW5kIDIwMDdJbnRlcm5ldFVzYWdlLiBJIGRlY2lkZWQgdG8gdXNlIGEgbGVmdCBqb2luIHRvIGpvaW4gdGhlc2UgdGhyZWUgdGFibGVzIGluIG9yZGVyIHRvIGRlbW9uc3RyYXRlIHRoZSBmdW5jdGlvbmFsaXR5IG9mIHRoZSBsZWZ0IGpvaW4uIEhvd2V2ZXIsIGEgcmlnaHQgam9pbiBvciBmdWxsIG91dGVyIGpvaW4gd291bGQgaGF2ZSB5aWVsZGVkIHRoZSBzYW1lIHJlc3VsdCBhcyB0aGUgcmVnaW9uIGNvbHVtbnMgYWxsIGNvbnRhaW5lZCB0aGUgc2FtZSBpbmZvcm1hdGlvbiBmb3IgdGhlc2UgdGhyZWUgZGF0YSBzZXRzLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KQWRkaXRpb25hbGx5LCBJIGRlY2lkZWQgdG8gY3JlYXRlIGEgcGFyYW1ldGVyIGZvciB0aGlzIGluc2lnaHQgZGV0YWlsaW5nIHRocmVlIGRpZmZlcmVudCBjYXRlZ29yaWVzOiBsb3csIG1lZGl1bSwgYW5kIGhpZ2ggZm9yIHRoZSBwZXJjZW50YWdlIG9mIGluZGl2aWR1YWxzIHRoYXQgYWNjZXNzZWQgdGhlIGludGVybmV0IGZyb20gaG9tZS4gVGhpcyBpcyBhbHNvIHNob3duIGluIHRoZSBiZWxvdyBzY3JlZW5zaG90Lg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9LUnNkUEx1LnBuZykNCg0KYGBge3J9DQpkZl81IDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigid2l0aCBxMSBhcyAoU0VMRUNUIGAyMDA3aW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyBBdmVyYWdlSW5jb21lMjAwNywgYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlcywgYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIGFzIEFjY2Vzc0luc2lkZUhvdXNlMjAwNw0KRlJPTSBgMjAwN2luY29tZV9jbGVhbmVkYA0KTEVGVCBKT0lOIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGAgT04gYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5yZWdpb24gPSBgMjAwN2luY29tZV9jbGVhbmVkYC5yZWdpb24pLA0KDQpxMiBhcyAoU0VMRUNUIHExLkF2ZXJhZ2VJbmNvbWUyMDA3LCBxMS5TdGF0ZXMsIHExLkFjY2Vzc0luc2lkZUhvdXNlMjAwNywgZmFjZWJvb2tfY2xlYW5lZC5mYWNlYm9va19wZW5ldHJhdGlvbiBhcyBGYWNlYm9va1BlbmV0cmF0aW9uDQpGUk9NIHExDQpMRUZUIEpPSU4gYGZhY2Vib29rX2NsZWFuZWRgIE9OIGBmYWNlYm9va19jbGVhbmVkYC5yZWdpb24gPSBxMS5TdGF0ZXMpDQoNClNFTEVDVCBxMi5BdmVyYWdlSW5jb21lMjAwNywgcTIuU3RhdGVzLCBxMi5BY2Nlc3NJbnNpZGVIb3VzZTIwMDcsIHEyLkZhY2Vib29rUGVuZXRyYXRpb24sDQpDQVNFDQpXSEVOIEFjY2Vzc0luc2lkZUhvdXNlMjAwNyA8IDU5IFRIRU4gJ0xPVycNCldIRU4gQWNjZXNzSW5zaWRlSG91c2UyMDA3ID4gNzAgVEhFTiAnSElHSCcNCkVMU0UgJ01FRElVTScNCkVORCBBUyBMb3dNZWRpdW1IaWdoSW50ZXJuZXRBY2Nlc3MyMDA3DQpGUk9NIHEyIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KDQpgYGANCg0KDQoqKlJlZm9ybWF0dGluZyBpbiBSKioNCg0KVGhlIG5leHQgc3RlcCBpbiB0aGUgZGF0YSBzY2llbmNlIHBpcGVsaW5lIGlzIHRvIGdhdGhlciB0aGUgY29sdW1ucyBpbnRvIGEgc2V0IG9mIGtleSB2YWx1ZSBwYWlycy4gSG93ZXZlciwgZm9yIHRoaXMgY3VycmVudCBpbnNpZ2h0LCBnYXRoZXJpbmcgd2FzIG5vdCBuZWVkZWQuDQoNCg0KKipVdGlsaXppbmcgZHBseXIgdG8gdHJhbnNmb3JtLCB2aXN1YWxpemUsIGFuZCBjb21tdW5pY2F0ZSoqDQoNClRoZSBmb2xsb3dpbmcgZ3JhcGggc2hvd3MgdGhhdCBzdGF0ZXMgd2l0aCBsb3cgaW50ZXJuZXQgdXNhZ2UgaW4gaG9tZSBhbHNvIHRlbmRlZCB0byBoYXZlIGEgbG93ZXIgYXZlcmFnZSBpbmNvbWVzIHdoaWxlIHN0YXRlcyB3aXRoIGhpZ2ggaW50ZXJuZXQgdXNhZ2UgdGVuZGVkIHRvIGhhdmUgaGlnaGVyIGF2ZXJhZ2UgaW5jb21lcy4gSG93ZXZlciwgaW4gdGhlIG1pZGRsZSBjYXRlZ29yeSwgdGhlcmUgd2VyZSB0d28gY2xlYXIgZGlzY2VybmlibGUgb3V0bGllcnMgdGhhdCBpbW1lZGlhdGVseSBzdHJ1Y2sgbWU6IEQuQy4gYW5kIENhbGlmb3JuaWEuDQoNCmBgYHtyfQ0KDQpyZW5kZXJQbG90KHtkZl81ICU+JSBnZ3Bsb3QoKSArIGdlb21fcG9pbnQobWFwcGluZz1hZXMoeD1Mb3dNZWRpdW1IaWdoSW50ZXJuZXRBY2Nlc3MyMDA3LCB5PUF2ZXJhZ2VJbmNvbWUyMDA3LCBjb2xvciA9IFN0YXRlcykpICsgZ2VvbV9ib3hwbG90KG1hcHBpbmc9YWVzKHg9TG93TWVkaXVtSGlnaEludGVybmV0QWNjZXNzMjAwNywgeT1BdmVyYWdlSW5jb21lMjAwNykpICsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEluY29tZSBieSBJbnRlcm5ldCBBY2Nlc3MgYXQgSG9tZSAoMjAwNykiLCB4PSJDYXRlZ29yeSBvZiBJbnRlcm5ldCBBY2Nlc3MiLCB5PSJBdmVyYWdlIEluY29tZSIpfSkNCg0KDQpgYGANCg0KSSBkZWNpZGVkIHRvIGV4cGxvcmUgdGhpcyBmdXJ0aGVyIGFuZCBzZWUgaWYgSSBjb3VsZCB1bmRlcnN0YW5kIHdoeSB0aGVzZSBvdXRsaWVycyBleGlzdGVkLiBJIGNyZWF0ZWQgYSBzZXQgb2YganVzdCB0aGVzZSB0d28gc3RhdGVzIGFuZCBjb21wYXJlZCB0aGVpciBGYWNlYm9vayBwZW5ldHJhdGlvbiBhbmQgaW50ZXJuZXQgdXNhZ2UuIEludGVyZXN0aW5nbHkgZW5vdWdoLCBJIGZvdW5kIHRoYXQgQ2FsaWZvcm5pYSB3YXMgb24gdGhlIGxvd2VyIGVuZCBvZiB0aGUgc2NhbGUgd2hpbGUgRC5DLiB3YXMgY29tcGxldGVseSBvbiB0aGUgY29tcGxldGUgb3Bwb3NpdGUgc2lkZSBhdCB0aGUgdmVyeSBoaWdoIGVuZCBvZiB0aGUgc2NhbGUuIEQuQy4ncyBudW1iZXIgc3RydWNrIG1lIGFzIHZlcnkgaW50ZXJlc3RpbmcgYXMgdGhlIHJlZ2lvbiBib2FzdGVkIDI2MCUgRmFjZWJvb2sgcGVuZXRyYXRpb24uDQoNCmBgYHtyfQ0KDQpyZW5kZXJQbG90KHtkZl81ICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlcyAlaW4lIGMoJ0Rpc3RyaWN0IG9mIENvbHVtYmlhJywgJ0NhbGlmb3JuaWEnKSkgJT4lIGdncGxvdChtYXBwaW5nID1hZXMoeD1Mb3dNZWRpdW1IaWdoSW50ZXJuZXRBY2Nlc3MyMDA3LCB5PUF2ZXJhZ2VJbmNvbWUyMDA3LCBmaWxsPVN0YXRlcykpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGZhY2V0X3dyYXAoflN0YXRlcykrIGxhYnModGl0bGUgPSAiQXZlcmFnZSBJbmNvbWUgYnkgSW50ZXJuZXQgQWNjZXNzIGF0IEhvbWUgKENhbGlmb3JuaWEgLyBELkMuKSIsIHg9IkNhdGVnb3J5IG9mIEludGVybmV0IEFjY2VzcyIsIHk9IkF2ZXJhZ2UgSW5jb21lIil9KQ0KDQpyZW5kZXJQbG90KHtkZl81ICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlcyAlaW4lIGMoJ0Rpc3RyaWN0IG9mIENvbHVtYmlhJywgJ0NhbGlmb3JuaWEnKSkgJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHg9RmFjZWJvb2tQZW5ldHJhdGlvbiwgeT1BdmVyYWdlSW5jb21lMjAwNywgY29sb3IgPSBTdGF0ZXMsIHNpemUgPSAzMCkpICsgZ2VvbV9wb2ludCgpKyBsYWJzKHRpdGxlID0gIkZhY2Vib29rIFBlbmV0cmF0aW9uIFdpdGggUmVzcGVjdCB0byBBdmVyYWdlIEluY29tZSAoQ2FsaWZvcm5pYSAvIEQuQy4pIiwgeD0iRmFjZWJvb2sgUGVuZXRyYXRpb24iLCB5PSJBdmVyYWdlIEluY29tZSIpfSkNCg0KYGBgDQoNCkF0IGZpcnN0IGdsYW5jZSwgSSB0aG91Z2h0IHRoaXMgbnVtYmVyIHdhcyBhIG1pc3Rha2UgYXMgaXQgd2FzIGdyZWF0ZXIgdGhhbiAxMDAlLiBUbyBleHBsb3JlIHRoaXMgZnVydGhlciwgSSB3ZW50IGJhY2sgdG8gdGhlIHdlYnNpdGUgSSBwdWxsZWQgdGhpcyBkYXRhIHNldCBmcm9tIGFuZCBmb3VuZCB0aGlzIHF1b3RlIGluIHRoZSBmb290bm90ZTogIlBsZWFzZSBub3RlIEQuQy4gcGVuZXRyYXRpb24gZGF0YSBpcyBvdXQgb2YgbGltaXRzLCB0aGlzIGlzIHByb2JhYmx5IGR1ZSB0byBub24tcmVzaWRlbnQgRmFjZWJvb2sgdXNlcnMuICIgSW50ZXJlc3RpbmdseSBlbm91Z2gsIEQuQy4ncyBGYWNlYm9vayBwZW5ldHJhdGlvbiBudW1iZXIgd2FzIGluZmxhdGVkIGR1ZSB0byBjb21tdXRlcnMgY29taW5nIGludG8gdGhlIHJlZ2lvbiwgbW9zdCBsaWtlbHkgZm9yIHdvcmsuIFRoZXJlZm9yZSwgdGhlIEZhY2Vib29rIHBlbmV0cmF0aW9uIG51bWJlciB3YXMgYm9hc3RlZCBhcyBhIG11bHRpcGxlIG9mIHRoZSByZXNpZGVudGlhbCBwb3B1bGF0aW9uIGluIEQuQy4NCg0KSSBmb3VuZCB0aGlzIGluc2lnaHQgdG8gYmUgZXZlbiBtb3JlIGludGVyZXN0aW5nIGFmdGVyIEkgY3JlYXRlZCBhIHRhYmxlIGNhbGN1bGF0aW9uIChtdXRhdGUpIG9mIHRoZSBjdW11bGF0aXZlIHN1bSBhbmQgY3VtdWxhdGl2ZSBkaXN0YW5jZSBvZiBGYWNlYm9vayBwZW5ldHJhdGlvbiBmaWd1cmVzIGFuZCBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUuIFRoZXJlIHdhcyBhIHZlcnkgYXBwYXJlbnQgYW5kIHN0cm9uZyByZWxhdGlvbnNoaXAgYmV0d2VlbiBib3RoIGZpZ3VyZXMgaW4gYm90aCBjYWxjdWxhdGlvbnMNCg0KYGBge3J9DQoNCnJlbmRlclBsb3Qoe2RmXzUgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGVzICE9ICdEaXN0cmljdCBvZiBDb2x1bWJpYScgJiBTdGF0ZXMgIT0gJ0NhbGlmb3JuaWEnKSAlPiUgZHBseXI6Om11dGF0ZShDdW1hbGF0aXZlU3VtRmFjZWJvb2sgPSBjdW1zdW0oRmFjZWJvb2tQZW5ldHJhdGlvbiksIEN1bWFsYXRpdmVTdW1JbmNvbWUgPSBjdW1zdW0oQXZlcmFnZUluY29tZTIwMDcpKSAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1DdW1hbGF0aXZlU3VtRmFjZWJvb2ssIHk9Q3VtYWxhdGl2ZVN1bUluY29tZSwgY29sb3I9U3RhdGVzKSkgKyBnZW9tX3BvaW50KCkrIGxhYnModGl0bGUgPSAiQ3VtYWxhdGl2ZSBTdW0gb2YgRmFjZWJvb2sgUGVuZXRyYXRpb24gKC1ELmMuLy1DYWxpZm9ybmlhKSIsIHg9IiBDdW1hbGF0aXZlIFN1bSBvZiBGYWNlYm9vayBQZW5ldHJhdGlvbiIsIHk9IkN1bWFsYXRpdmUgU3VtIG9mIEF2ZXJhZ2UgSW5jb21lIil9KQ0KDQoNCmRmXzVhIDwtIGRmXzUgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGVzICE9ICdEaXN0cmljdCBvZiBDb2x1bWJpYScgJiBTdGF0ZXMgIT0gJ0NhbGlmb3JuaWEnKSAlPiUgZHBseXI6Om11dGF0ZShBcnJhbmdlZEN1bWFsYXRpdmVEaXN0YW5jZUZhY2Vib29rID0gY3VtZV9kaXN0KEZhY2Vib29rUGVuZXRyYXRpb24pLCBDdW1hbGF0aXZlRGlzdGFuY2VJbmNvbWUgPSBjdW1lX2Rpc3QoQXZlcmFnZUluY29tZTIwMDcpKSAlPiUgYXJyYW5nZShBcnJhbmdlZEN1bWFsYXRpdmVEaXN0YW5jZUZhY2Vib29rKSAgDQoNCmRmXzVhJFN0YXRlcyA8LSBmYWN0b3IoZGZfNWEkU3RhdGVzLCBsZXZlbHM9ZGZfNWEkU3RhdGVzKQ0KDQpyZW5kZXJQbG90KHtkZl81YSAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1BcnJhbmdlZEN1bWFsYXRpdmVEaXN0YW5jZUZhY2Vib29rLCB5PUN1bWFsYXRpdmVEaXN0YW5jZUluY29tZSwgY29sb3I9U3RhdGVzKSkgKyBnZW9tX3BvaW50KCkrIGxhYnModGl0bGUgPSAiQ3VtYWxhdGl2ZSBEaXN0YW5jZSBvZiBGYWNlYm9vayBQZW5ldHJhdGlvbiAoLUQuYy4vLUNhbGlmb3JuaWEpIiwgeD0iIEN1bWFsYXRpdmUgRGlzdGFuY2Ugb2YgRmFjZWJvb2sgUGVuZXRyYXRpb24iLCB5PSJDdW1hbGF0aXZlIERpc3RhbmNlIG9mIEF2ZXJhZ2UgSW5jb21lIil9KQ0KDQoNCmBgYA0KDQoqKiAgICoqDQojIyAqKlJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uLCBJbnRlcm5ldCBQZW5ldHJhdGlvbiwgYW5kIDIwLTI0IFBvcHVsYXRpb24gLSAyMDEyKioNCg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkZvciB0aGlzIGluc2lnaHQsIEkgZGVjaWRlZCB0byB1c2UgaW5mb3JtYXRpb24gZnJvbSB0d28gZGlmZmVyZW50IGRhdGEgdGFibGVzOiBGYWNlYm9va1VzYWdlLCBhbmQgMjAxMlBvcHVsYXRpb24uIEkgdXNlZCBhbiBpbm5lciBqb2luIHRvIGpvaW4gdGhlc2UgdHdvIHRhYmxlcyB0b2dldGhlciBvbiByZWdpb24uIFRoZSBjb2RlIGZvciB0aGlzIGlzIHNob3duIGluIHRoZSBzY3JlbnNob3QgYmVsb3cuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL09VcEc5VGoucG5nKQ0KDQpgYGB7cn0NCg0KZGZfNiA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgZmFjZWJvb2tfY2xlYW5lZGAuZmFjZWJvb2tfcGVuZXRyYXRpb24gYXMgRmFjZWJvb2tQZW5ldHJhdGlvbiwgYGZhY2Vib29rX2NsZWFuZWRgLmludGVybmV0X3BlbmV0cmF0aW9uIGFzIEludGVybmV0UGVuZXRyYXRpb24sIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9lc3RpbWF0ZV9hZ2VfMjBfdG9fMjRfeWVhcnMgYXMgUG9wdWxhdGlvbjIwdG8yNCwgYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZXMNCkZST00gYGZhY2Vib29rX2NsZWFuZWRgDQpKT0lOIDIwMTJwb3B1bGF0aW9uX2NsZWFuZWQgb24gYGZhY2Vib29rX2NsZWFuZWRgLnJlZ2lvbiA9IGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpBIHRyZWUgbWFwIG9mIEZhY2Vib29rIHBlbmV0cmF0aW9uIHJlbGF0aXZlIHRvIGludGVybmV0IHBlbmV0cmF0aW9uIHNob3dzIHRoYXQgdGhlaXIgZG9lc24ndCBzZWVtIHRvIGJlIGEgY29uY3JldGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR3by4gVGhpcyBpcyBpbnRlcmVzdGluZyBhcyBvbmUgd291bGQgaW1hZ2luZSB0aGF0IGFzIGludGVybmV0IHBlbmV0cmF0aW9uIGluY3JlYXNlcywgRmFjZWJvb2sgcGVuZXRyYXRpb24gd291bGQgYWxzbyBpbmNyZWFzZS4NCg0KYGBge3J9DQoNCmRmXzZhIDwtIGRmXzYgJT4lIGFycmFuZ2UoRmFjZWJvb2tQZW5ldHJhdGlvbikNCmRmXzZhJFN0YXRlcyA8LSBmYWN0b3IoZGZfNmEkU3RhdGVzLCBsZXZlbHM9ZGZfNmEkU3RhdGVzKQ0KDQoNCnJlbmRlclBsb3Qoew0KIGdncGxvdDI6OmdncGxvdChkYXRhPWRmXzZhLCBtYXBwaW5nID0gYWVzKGFyZWEgPSBGYWNlYm9va1BlbmV0cmF0aW9uLCBmaWxsID0gSW50ZXJuZXRQZW5ldHJhdGlvbiwgbGFiZWw9U3RhdGVzKSkgKw0KIGdlb21fdHJlZW1hcCgpICsNCiBnZW9tX3RyZWVtYXBfdGV4dChmb250ZmFjZSA9ICJpdGFsaWMiLCBjb2xvdXIgPSAid2hpdGUiLCBwbGFjZSA9ICJ0b3BsZWZ0IikrIGxhYnModGl0bGUgPSAiVHJlZSBNYXAgb2YgRmFjZWJvb2sgUGVuZXRyYXRpb24gUmVsYXRpdmUgdG8gSW50ZXJuZXQgUGVuZXRyYXRpb24gKGZpbGwgPSBJbnRlcm5ldCBQZW5ldHJhdGlvbiwgYXJlYSA9IEZhY2Vib29rIFBlbmV0cmF0aW9uIikNCn0pDQoNCmBgYA0KDQpIb3dldmVyLCBhcyB0aGUgc2Vjb25kIHRyZWUgbWFwIHNob3dzLCB0aGVyZSBzZWVtcyB0byBiZSBhIG1vcmUgZGlzY2VybmlibGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRmFjZWJvb2sgcGVuZXRyYXRpb24gYW5kIHRoZSBwb3B1bGF0aW9uIGFnZSAyMC0yNCBwZXJjZW50YWdlLiBBcyB0aGF0IHBvcHVsYXRpb24gcGVuZXRyYXRpb24gaW5jcmVhc2VzLCBGYWNlYm9vayBwZW5ldHJhdGlvbiBzZWVtcyB0byBhbHNvIGluY3JlYXNlLiBUaGlzIGlzIGNsZWFyIGluIHN0YXRlcyBsaWtlIERpc3RyaWN0IG9mIENvbHVtYmlhIGFuZCBOb3J0aCBEYWtvdGEgd2hpY2ggaGF2ZSB2ZXJ5IGhpZ2ggcGVyY2VudGFnZXMgb2YgMjAtMjQgeWVhciBvbGRzIGFzIHdlbGwgYXMgYSBoaWdoIEZhY2Vib29rIHBlbmV0cmF0aW9uLiBUaGlzIHJlbGF0aW9uc2hpcCBpcyBtb3N0IGxpa2VseSBhdHRyaWJ1dGVkIHRvIHRoZSBmYWN0IHRoYXQgbXVjaCBvZiB0aGUgcG9wdWxhdGlvbiBvbiBGYWNlYm9vayBpcyB5b3VuZyBhbmQgaW4gYmV0d2VlbiB0aGUgYWdlcyBvZiAxOSBhbmQgMzAuDQoNCmBgYHtyfQ0KDQpyZW5kZXJQbG90KHsNCiBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YT1kZl82YSwgbWFwcGluZyA9IGFlcyhhcmVhID0gRmFjZWJvb2tQZW5ldHJhdGlvbiwgZmlsbCA9IFBvcHVsYXRpb24yMHRvMjQsIGxhYmVsPVN0YXRlcykpICsNCiBnZW9tX3RyZWVtYXAoKSArDQogZ2VvbV90cmVlbWFwX3RleHQoZm9udGZhY2UgPSAiaXRhbGljIiwgY29sb3VyID0gIndoaXRlIiwgcGxhY2UgPSAidG9wbGVmdCIpICsgIGxhYnModGl0bGUgPSAiVHJlZSBNYXAgb2YgRmFjZWJvb2sgUGVuZXRyYXRpb24gUmVsYXRpdmUgdG8gMjAtMjQgUG9wdWxhdGlvbiAoZmlsbCA9IDIwIHRvIDI0IFBvcHVsYXRpb24sIGFyZWEgPSBGYWNlYm9vayBQZW5ldHJhdGlvbiIpDQp9KQ0KDQpgYGANCg0KKiogICAqKg0KIyMgKipSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYWxlIHRvIEZlbWFsZSBSYXRpbyBhbmQgSW50ZXJuZXQgUGVuZXRyYXRpb24gKEJsZW5kaW5nIERhdGEgKyBJZmVsc2UgKyBMT0QgKSoqDQoNCioqSW5wdXR0aW5nIHRoZSBDU1YgaW50byBSKioNCg0KRm9yIHRoaXMgaW5zaWdodCwgSSB1c2VkIGRhdGEgZnJvbSB0d28gc291cmNlczogRmFjZWJvb2tVc2FnZSBhbmQgMjAxMlBvcHVsYXRpb24uIEluIFRhYmxlYXUsIEkgZGVjaWRlZCB0byBibGVuZCB0aGVzZSB0d28gZGF0YSBzb3VyY2VzIGluc3RlYWQgb2Ygam9pbmluZyB0aGVtIHRvZ2V0aGVyLiBUaGlzIGlzIHNob3duIGluIHRoZSBzY3JlZW5zaG90IGJlbG93Lg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9VTmlQVlhaLnBuZykNCg0KQXMgY2FuIGJlIHNlZW4gaW4gdGhlIGFib3ZlIHNjcmVlbnNob3QsIGJvdGggb2YgdGhlIGRhdGEgc291cmNlcyBoYXZlIGJlZW4gYmxlbmRlZCBvbiB0aGUgcmVnaW9uIGZpZWxkLg0KDQpGb3IgUiBkb2N1bWVudGF0aW9uIHB1cnBvc2VzLCBJIGRlY2lkZWQgdG8gZG8gYW4gaW5uZXIgam9pbiBvZiB0aGUgdHdvIGRhdGFzZXRzLg0KDQpGb3IgdGhpcyBpbnNpZ2h0LCBJIGFsc28gZGVjaWRlZCB0byBjcmVhdGUgYSB2aWV3IGxldmVsIGNhbGN1bGF0ZWQgZmllbGQgdGhhdCB0YWtlcyB0aGUgbWFsZSB0b3RhbCBwb3B1bGF0aW9uIGFuZCBkaXZpZGVzIGl0IGJ5IHRoZSBmZW1hbGUgdG90YWwgcG9wdWxhdGlvbi4gVGhpcyBpcyBzaG93biBhcyBwYXJ0IG9mIHRoZSBxdWVyeSBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vbjhTVEwxOC5wbmcpDQoNCg0KDQpgYGB7cn0NCg0KZGZfNyA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgZmFjZWJvb2tfY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlcywgYGZhY2Vib29rX2NsZWFuZWRgLmludGVybmV0X3BlbmV0cmF0aW9uIGFzIEludGVybmV0UGVuZXRyYXRpb24sIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC5tYWxlX3RvdGFsX3BvcHVsYXRpb24gYXMgTWFsZVBvcHVsYXRpb24sIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC5mZW1hbGVfdG90YWxfcG9wdWxhdGlvbiBhcyBGZW1hbGVQb3B1bGF0aW9uLCBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAubWFsZV90b3RhbF9wb3B1bGF0aW9uIC8gYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLmZlbWFsZV90b3RhbF9wb3B1bGF0aW9uIGFzIE1GUmF0aW8NCkZST00gYGZhY2Vib29rX2NsZWFuZWRgDQpKT0lOIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYCBPTiBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uID0gYGZhY2Vib29rX2NsZWFuZWRgLnJlZ2lvbiIpLCBkYXRhc2V0PXByb2plY3QpDQoNCg0KYGBgDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpBcyB0aGUgbWFwIGJlbG93IHNob3dzLCBpdCBzZWVtcyB0aGF0IHRoZSBtYWxlIHRvIGZlbWFsZSByYXRpbyBpcyBsZWFzdCBvbiB0aGUgZWFzdCBjb2FzdCBhbmQgaW5jcmVhc2VzIHNsb3dseSBhcyBvbmUgZ29lcyB0b3dhcmRzIHRoZSB3ZXN0IGNvYXN0LiBleGNsdWRpbmcgT3JlZ29uIGFuZCBXYXNoaW5ndG9uIFRoaXMgbWF5IGJlIGJlY2F1c2UgdGhlcmUgYXJlIG9wcG9ydHVuaXRpZXMgaW4gdGhlIGVhc3QgY29hc3QgYW5kIGluIHRob3NlIHR3byBzdGF0ZXMgdGhhdCBhcmUgbW9yZSBhdHRyYWN0aXZlIHRvIGZlbWFsZXMgYW5kIHZpY2UgdmVyc2EgZm9yIG1hbGVzLiBIb3dldmVyLCBpdCdzIHZlcnkgaW50ZXJlc3RpbmcgdG8gc2VlIHRoYXQgYWNyb3NzIHRoZSB3aG9sZSBlYXN0IGNvYXN0LCBmZW1hbGVzIGFyZSBjb25zaXN0ZW50bHkgdGhlIG1ham9yaXR5IHNleC4NCg0KTm90ZTogdG8gY2FsY3VsYXRlIHRoaXMgZmllbGQgaW4gVGFibGVhdSwgSSB1c2VkIGEgZml4ZWQgTE9EIGNhbGN1bGF0aW9uLiBJbiB0aGlzIGZvbGxvd2luZyBtYXAgZXhhbXBsZSwgSSB1c2VkIGdyb3VwX2J5IGJ5IFN0YXRlcyB0byBkbyB0aGUgc2FtZSB0aGluZy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vWTM5UDRIcC5wbmcpDQoNCmBgYHtyfQ0KDQoNCmRmXzdhIDwtIGRmXzcgJT4lIGRwbHlyOjpzZWxlY3QoU3RhdGVzLCBNRlJhdGlvKSAlPiUgZ3JvdXBfYnkoU3RhdGVzKQ0KDQoNCm5hbWVzKGRmXzdhKSA8LSBjKCJyZWdpb24iLCAidmFsdWUiKQ0KZGZfN2EkcmVnaW9uIDwtIHRvbG93ZXIoZGZfN2EkcmVnaW9uKQ0KZGZfN2EkcmVnaW9uIDwtIGdzdWIoIiAodS5zLiBzdGF0ZSkiLCAiIiwgZGZfN2EkcmVnaW9uLCBmaXhlZD1UUlVFKQ0KcmVuZGVyUGxvdCh7c3RhdGVfY2hvcm9wbGV0aChkZl83YSkgKyBsYWJzKHRpdGxlID0gIk1hbGUgdG8gRmVtYWxlIFJhdGlvIGJ5IFN0YXRlIil9KQ0KDQoNCmBgYA0KDQoNClRoaXMgbmV4dCBncmFwaCBzaG93cyBpbnRlcm5ldCBwZW5ldHJhdGlvbiBieSByZWdpb24uIEFzIGNhbiBiZSBzZWVuLCBpbnRlcm5ldCBwZW5ldHJhdGlvbiBzZWVtcyB0byBiZSB0aGUgaGlnaGVzdCBpbiB0aGUgbm9ydGggZWFzdCBhbmQgaW4gc29tZSBzdGF0ZXMgb24gdGhlIHdlc3QgY29hc3QuIHN1Y2ggYXMgT3JlZ29uIGFuZCBXYXNoaW5ndG9uIFRoZXNlIGFyZSBhbHNvIGFyZWFzIHRoYXQgY29ycmVsYXRlIHdpdGggaGF2aW5nIGxvd2VyIG1hbGUgdG8gZmVtYWxlIHJhdGlvcy4NCg0KDQpgYGB7cn0NCg0KZGZfN2IgPC0gZGZfNyAlPiUgZHBseXI6OnNlbGVjdChTdGF0ZXMsIEludGVybmV0UGVuZXRyYXRpb24pICU+JSBncm91cF9ieShTdGF0ZXMpDQoNCg0KbmFtZXMoZGZfN2IpIDwtIGMoInJlZ2lvbiIsICJ2YWx1ZSIpDQpkZl83YiRyZWdpb24gPC0gdG9sb3dlcihkZl83YiRyZWdpb24pDQpkZl83YiRyZWdpb24gPC0gZ3N1YigiICh1LnMuIHN0YXRlKSIsICIiLCBkZl83YiRyZWdpb24sIGZpeGVkPVRSVUUpDQpyZW5kZXJQbG90KHtzdGF0ZV9jaG9yb3BsZXRoKGRmXzdiKSsgbGFicyh0aXRsZSA9ICJJbnRlcm5ldCBQZW5ldHJhdGlvbiBieSBTdGF0ZSIpfSkNCg0KDQpgYGANCg0KSG93ZXZlciwgaW50ZXJlc3RpbmdseSBlbm91Z2gsIGFyZWFzIHRoYXQgYXJlIG1hbGUgZG9taW5hbnQgYXMgc2hvd24gaW4gdGhlIGdyYXBoIGJlbG93IHNlZW0gdG8gaGF2ZSBoaWdoZXIgYXZlcmFnZSBpbnRlcm5ldCBwZW5ldHJhdGlvbiB0aGFuIGFyZWFzIHRoYXQgYXJlIGZlbWFsZSBkb21pbmFudC4gVGhlcmVmb3JlLCB3ZSBhcmUgbW9zdCBsaWtlbHkgbWlzc2luZyBzb21lIHNvcnQgb2Yga2V5IHRyZW5kIC8gaW5mb3JtYXRpb24gdGhhdCBleHBsYWlucyB0aGUgcmVsYXRpb25zaGlwIGluIHRoZSBmaXJzdCB0d28gZ3JhcGhzIHN1Y2ggYXMgYSBsdXJraW5nIHZhcmlhYmxlLg0KDQpOb3RlOiB0byBjYWxjdWxhdGUgd2hldGhlciBvciBub3QgdGhlcmUgd2FzIGEgbWFsZSAvIGZlbWFsZSBtYWpvcml0eSwgSSB1c2VkIHRoZSBpZmVsc2UgZnVuY3Rpb24gdW5kZXIgbXV0YXRlIGFzIHNob3duIGluIHRoZSBzY3JlZW5zaG90IGJlbG93Lg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9PWW94ejVsLnBuZykNCg0KDQpgYGB7cn0NCg0KDQpkZl83YyA8LSBkZl83ICU+JSBkcGx5cjo6bXV0YXRlKE1GTWFqb3JpdHk9IGlmZWxzZShNRlJhdGlvPD0xLCAnRmVtYWxlTWFqb3JpdHknLCBpZmVsc2UoTUZSYXRpbz4xLCAnTWFsZU1ham9yaXR5JywgJ05BJykpKQ0KDQpyZW5kZXJQbG90KHtkZl83YyAlPiUgZ2dwbG90KCkgKyBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyh4PU1GTWFqb3JpdHksIHk9SW50ZXJuZXRQZW5ldHJhdGlvbikpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9TUZNYWpvcml0eSwgeT1JbnRlcm5ldFBlbmV0cmF0aW9uLCBjb2xvciA9IFN0YXRlcykpK2xhYnModGl0bGUgPSAiSW50ZXJuZXQgUGVuZXRyYXRpb24gYnkgTWFsZSAvIEZlbWFsZSBNYWpvcml0eSIsIHg9IiBNYWxlIC8gRmVtYWxlIE1ham9yaXR5IiwgeT0iSW50ZXJuZXQgUGVuZXRyYXRpb24iKX0pDQoNCg0KYGBgDQoNCioqICAgKioNCiMjICoqUmVsYXRpb25zaGlwIGJldHdlZW4gSW4taG9tZSBhbmQgT3V0IG9mIEhvbWUgSW50ZXJuZXQgQWNjZXNzIGZvciAyMDA3LzIwMTIqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkZvciB0aGlzIGluc2lnaHQsIEkgdXNlZCBkYXRhIGZyb20gdHdvIHRhYmxlczogMjAwN0ludGVybmV0VXNhZ2UgYW5kIDIwMTJJbnRlcm5ldFVzYWdlLiBJIHVzZWQgYW4gaW5uZXIgam9pbiBvbiBUYWJsZWF1IGluIG9yZGVyIHRvIGpvaW4gdGhlc2UgdHdvIHRhYmxlcyB0b2dldGhlciBvbiByZWdpb24uIEhvd2V2ZXIsIEkgdXNlZCBhIHJpZ2h0IGpvaW4gaW4gdGhlIGZvbGxvd2luZyBkYXRhLndvcmxkIFNRTCBpbiBvcmRlciB0byBkZW1vbnN0cmF0ZSBpdHMgZnVuY3Rpb25hbGl0eS4gQmVjYXVzZSB0aGUgbm9tZW5jbGF0dXJlIGFuZCByb3cgdmFsdWVzIHdlcmUgdGhlIHNhbWUgZm9yIHRoZSBjb2x1bW4gSSB3YXMgam9pbmluZyBvbiwgYSBsZWZ0IGpvaW4gb3IgYSBpbm5lciBqb2luIHdvdWxkIGhhdmUgcmVzdWx0ZWQgaW4gdGhlIHNhbWUgb3V0cHV0Lg0KDQpBZGRpdGlvbmFsbHksIEkgY3JlYXRlZCBhIHZpZXctbGV2ZWwgY2FsY3VsYXRlZCBmaWVsZCB0aGF0IHRha2VzIHRoZSBzdW0gb2YgdGhlIG51bWJlciBvZiBwZW9wbGUgdXNpbmcgdGhlIGludGVybmV0IGluIGhvbWUgYW5kIGRpdmlkZXMgaXQgYnkgdGhlIHN1bSBvZiB0aGUgbnVtYmVyIG9mIHBlb3BsZSB1c2luZyB0aGUgaW50ZXJuZXQgb3V0IG9mIHRoZSBob21lLiBUaGUgZm9sbG93aW5nIHNjcmVlbnNob3Qgc2hvd3MgdGhhdCBjYWxjdWxhdGlvbiBmb3IgMjAwNyBhbmQgMjAxMiBkYXRhIHJlc3BlY3RpdmVseS4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vYXNqVWh1NC5wbmcpDQoNCg0KYGBge3J9DQoNCmRmXzggPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCigid2l0aCBgcTFgIGFzIChTRUxFQ1QgYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5yZWdpb24gYXMgU3RhdGVzLCBgMjAwN2ludGVybmV0X2NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X291dHNpZGVfb2ZfaG91c2Vob2xkIGFzIDIwMDdBY2Nlc3NPdXRzaWRlSG9tZSwgYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5udW1iZXJfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgYXMgMjAwN0FjY2Vzc0Zyb21Ib21lLA0KYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5udW1iZXJfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9vdXRzaWRlX29mX2hvdXNlaG9sZCBhcyAyMDEyQWNjZXNzT3V0c2lkZUhvbWUsIGAyMDEyaW50ZXJuZXRfY2xlYW5lZGAubnVtYmVyX29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIGFzIDIwMTJBY2Nlc3NGcm9tSG9tZQ0KRlJPTSBgMjAwN2ludGVybmV0X2NsZWFuZWRgDQpSSUdIVCBKT0lOIGAyMDEyaW50ZXJuZXRfY2xlYW5lZGAgb24gYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5yZWdpb24gPSBgMjAxMmludGVybmV0X2NsZWFuZWRgLnJlZ2lvbikNCg0KU0VMRUNUIGBxMWAuU3RhdGVzLCBzdW0oYHExYC4yMDA3QWNjZXNzRnJvbUhvbWUpL3N1bShgcTFgLjIwMDdBY2Nlc3NPdXRzaWRlSG9tZSkgYXMgQWNjZXNzUmF0aW8yMDA3LCBzdW0oYHExYC4yMDEyQWNjZXNzRnJvbUhvbWUpL3N1bShgcTFgLjIwMTJBY2Nlc3NPdXRzaWRlSG9tZSkgYXMgQWNjZXNzUmF0aW8yMDEyDQpGUk9NIGBxMWAgR1JPVVAgQlkgYHExYC5TdGF0ZXMiKSwgDQoNCmRhdGFzZXQ9cHJvamVjdCkNCg0KDQpgYGANCg0KDQoqKlJlZm9ybWF0dGluZyBpbiBSKioNCg0KVGhlIG5leHQgc3RlcCBpbiB0aGUgZGF0YSBzY2llbmNlIHBpcGVsaW5lIGlzIHRvIGdhdGhlciB0aGUgY29sdW1ucyBpbnRvIGEgc2V0IG9mIGtleSB2YWx1ZSBwYWlycy4gVGhlIGNvZGUgZm9yIHRoaXMgaXMgc2hvd24gYmVsb3cuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL2I5YzEyWUwucG5nKQ0KDQpgYGB7cn0NCg0KZGZfOSA8LSBkZl84ICU+JXRpZHlyOjpnYXRoZXIoIlllYXJBY2Nlc3NSYXRpbyIsICJSYXRpbyIsCS0xKQ0KDQoNCmBgYA0KDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpJbiB0aGUgZm9sbG93aW5nIHNldCBvZiBncmFwaHMsIHRoZSBwbG90IG9mIDIwMTIgcmVnaW9uIHZlcnN1cyB0aGUgcmF0aW8gaXMgdGhlIGJvdHRvbSBwbG90IHdoaWxlIDIwMDcgcmVnaW9uIHZlcnN1cyB0aGUgcmF0aW8gaXMgdGhlIHRvcCBwbG90LiBBcyBjYW4gYmUgc2VlbiwgZm9yIDIwMTIsIGV2ZXJ5IHNpbmdsZSBzdGF0ZSBpcyBiZWxvdyB0aGUgMS4wMCBjb25zdGFudCBsaW5lIHdoaWNoIHNob3dzIHRoYXQgYWxsIHN0YXRlcyBoYXZlIG1vcmUgcGVvcGxlIHVzaW5nIHRoZSBpbnRlcm5ldCBvdXQgb2YgdGhlIGhvbWUgdGhhbiBpbiB0aGUgaG9tZS4gVGhlIHBsb3QgZm9yIDIwMDcgcGFpbnRzIGEgZGlmZmVyZW50IHN0b3J5IHdoZXJlIGFsbW9zdCBldmVyeSBzaW5nbGUgc3RhdGUgaXMgYWJvdmUgdGhlIDEuMDAgY29uc3RhbnQgbGluZSBhY2NlbnR1YXRpbmcgdGhhdCBtb3JlIHBlb3BsZSB1c2UgdGhlIGludGVybmV0IGluIHRoZSBob21lLiBUaGlzIGRldmVsb3BtZW50IGlzIGludGVyZXN0aW5nIGFuZCBpcyBtb3N0IGxpa2VseSBjYXVzZWQgYnkgc29tZSBsdXJraW5nIHZhcmlhYmxlLiBJIGJlbGlldmUgaXQgbWF5IGJlIGR1ZSB0byB0aGUgcHJldmFsZW5jZSBvZiBpbnRlcm5ldCB1c2FnZSBpbiB0aGUgd29yayBwbGFjZSBvdmVyIHRpbWUuIFRoaXMgaXMgdmVyeSBjb3VudGVyLWludHVpdGl2ZSB0byB3aGF0IEkgaW5pdGlhbGx5IHRob3VnaHQuIEkgYmVsaWV2ZWQgdGhhdCBhcyBjb21wdXRlcnMgYW5kIGludGVybmV0IGFjY2VzcyBnb3QgY2hlYXBlciwgbW9yZSBwZW9wbGUgd291bGQgdXNlIGl0IGluLWhvbWUgd2hpY2ggZG9lcyBub3Qgc2VlbSB0byBiZSB0aGUgY2FzZS4NCg0KQWRkaXRpb25hbCBub3RlOiBJIHVzZWQgYSByZWd1bGFyIGV4cHJlc3Npb24gb24gdGhlIGdhdGhlcmVkIGRhdGEgZnJhbWUgdG8gZmlsdGVyIHJvd3MgdGhhdCBjb250YWluZWQgYW55IGNoYXJhY3RlciwgdGhlbiAxMiAoMjAxMikgYXMgd2VsbCBhcyBhbnkgY2hhcmFjdGVyLCB0aGVuIDA3ICgyMDA3KSB0byBnZXQgcmlkIG9mIHRoZSBhcHByb3ByaWF0ZSByb3dzIGZyb20gdGhlIHRhYmxlLiBUaGUgY29kZSBmb3IgdGhhdCBpcyBzaG93biBiZWxvdy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vZDBPQkRkZy5wbmcpDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL3FJeXVDWUkucG5nKQ0KDQoNCg0KYGBge3J9DQpkZl84YSA8LSBkZl85ICU+JSBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiLioxMiIsIFllYXJBY2Nlc3NSYXRpbykpICU+JSBkcGx5cjo6YXJyYW5nZShSYXRpbykNCg0KZGZfOGEkU3RhdGVzIDwtIGZhY3RvcihkZl84YSRTdGF0ZXMsIGxldmVscz1kZl84YSRTdGF0ZXMpDQoNCg0KcmVuZGVyUGxvdCh7ZGZfOGEgJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHg9U3RhdGVzLCB5PVJhdGlvLCBjb2xvciA9IFN0YXRlcykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrIGxhYnModGl0bGUgPSAiMjAwNyBBY2Nlc3MgRnJvbSBIb21lIHRvIDIwMDcgQWNjZXNzIE91dHNpZGUgb2YgSG9tZSIsIHg9IlN0YXRlIiwgeT0iQWNjZXNzIFJhdGlvIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MS4wMCwgY29sb3IgPSAiYmx1ZSIpfSkNCg0KDQoNCmRmXzhiIDwtIGRmXzkgJT4lIGRwbHlyOjpmaWx0ZXIoIWdyZXBsKCIuKjA3IiwgWWVhckFjY2Vzc1JhdGlvKSklPiUgZHBseXI6OmFycmFuZ2UoUmF0aW8pDQoNCmRmXzhiJFN0YXRlcyA8LSBmYWN0b3IoZGZfOGIkU3RhdGVzLCBsZXZlbHM9ZGZfOGIkU3RhdGVzKQ0KDQoNCnJlbmRlclBsb3Qoe2RmXzhiICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PVN0YXRlcywgeT1SYXRpbywgY29sb3IgPSBTdGF0ZXMpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpKyBsYWJzKHRpdGxlID0gIjIwMTIgQWNjZXNzIEZyb20gSG9tZSB0byAyMDEyIEFjY2VzcyBPdXRzaWRlIG9mIEhvbWUiLCB4PSJTdGF0ZSIsIHk9IkFjY2VzcyBSYXRpbyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTEuMDAsIGNvbG9yID0gImJsdWUiKX0pDQoNCmBgYA0KDQpUbyBmdXJ0aGVyIGJhY2sgdGhpcyBwb2ludCwgSSBkZWNpZGVkIHRvIGNhbGN1bGF0ZSB0aGUgcGFuZSBtZWRpYW4gaW4gVGFibGVhdS4gV2l0aCBhIHBhbmUgbWVkaWFuIGJlbG93IDEgZm9yIDIwMTIsIHdlIHNlZSB0aGF0IHRoZSAibWlkZGxlIiBvciBhdmVyYWdlIHN0YXRlIHRlbmRzIHRvIGhhdmUgbW9yZSBwZW9wbGUgdXNlIHRoZSBpbnRlcm5ldCBvdXRzaWRlIHRoZSBob21lIGFzIGEgcmF0aW8gdG8gaW4gdGhlIGhvbWUuIFdpdGggYSBwYW5lIG1lZGlhbiBhYm92ZSAxIGZvciAyMDA3LCB3ZSBzZWUgdGhhdCB0aGUgIm1pZGRsZSIgb3IgYXZlcmFnZSBzdGF0ZSB0ZW5kcyB0byBoYXZlIG1vcmUgcGVvcGxlIHVzZSB0aGUgaW50ZXJuZXQgaW4gdGhlIGhvbWUgYXMgYSByYXRpbyB0byBvdXRzaWRlIHRoZSBob21lLg0KDQoNCmBgYHtyfQ0KDQpNZWRpYW5SYXRpb3MgPC0gZGZfOCAlPiUgc3VtbWFyaXplKE1lZGlhblJhdGlvMjAwNyA9IG1lZGlhbihgQWNjZXNzUmF0aW8yMDA3YCksIE1lZGlhblJhdGlvMjAxMiA9IG1lZGlhbihgQWNjZXNzUmF0aW8yMDEyYCkpDQoNCg0KcmVuZGVyRGF0YVRhYmxlKHsNCiAgRFQ6OmRhdGF0YWJsZShNZWRpYW5SYXRpb3MsIHJvd25hbWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9IGxpc3QoUmVzcG9uc2l2ZSA9IFRSVUUsIEZpeGVkSGVhZGVyID0gVFJVRSkNCiAgKQ0KfSkNCg0KcmVuZGVyUGxvdCh7ZGZfOGEgJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHg9U3RhdGVzLCB5PVJhdGlvLCBjb2xvciA9IFN0YXRlcykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkrIGxhYnModGl0bGUgPSAiMjAwNyBBY2Nlc3MgRnJvbSBIb21lIHRvIDIwMDcgQWNjZXNzIE91dHNpZGUgb2YgSG9tZSIsIHg9IlN0YXRlIiwgeT0iQWNjZXNzIFJhdGlvIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MS4wNTU0NCwgY29sb3IgPSAiYmx1ZSIpfSkNCg0KDQpyZW5kZXJQbG90KHtkZl84YiAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZXMsIHk9UmF0aW8sIGNvbG9yID0gU3RhdGVzKSkgKyBnZW9tX3BvaW50KCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsgbGFicyh0aXRsZSA9ICIyMDEyIEFjY2VzcyBGcm9tIEhvbWUgdG8gMjAxMiBBY2Nlc3MgT3V0c2lkZSBvZiBIb21lIiwgeD0iU3RhdGUiLCB5PSJBY2Nlc3MgUmF0aW8iKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLjkyNDkxNSwgY29sb3IgPSAiYmx1ZSIpfSkNCg0KDQpgYGANCg0KKiogICAqKg0KIyMgKipSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYXhpbXVtIERpc2NyZXBhbmN5IG9mIEludGVybmV0IEFjY2VzcyBPdXRzaWRlIEhvdXNlaG9sZCBhbmQgSW5jb21lIEJyYWNrZXRzKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpGb3IgdGhpcyBpbnNpZ2h0LCBJIHVzZWQgZGF0YSBmcm9tIHR3byB0YWJsZXM6IDIwMDdJbnRlcm5ldFVzYWdlIGFuZCAyMDA3SW5jb21lLiBJIHVzZWQgYW4gaW5uZXIgam9pbiBvbiBUYWJsZWF1IHRvIGpvaW4gdGhlc2UgdHdvIGRhdGEgc2V0cyB0b2dldGhlci4NCg0KSW4gdGhlIGZvbGxvd2luZyBzY3JlZW5zaG90LCBJIGNyZWF0ZWQgYSBjYWxjdWxhdGVkIGZpZWxkIGluIG9yZGVyIHRvIGJpbiB0b2dldGhlciByZWdpb25zIHdpdGggbG93IGF2ZXJhZ2UgbWVkaWFuIGluY29tZXMsIG1lZGl1bSBhdmVyYWdlIG1lZGlhbiBpbmNvbWVzLCBhbmQgaGlnaCBhdmVyYWdlIG1lZGlhbiBpbmNvbWVzLg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9Ka3dOVFNuLnBuZykNCg0KDQpgYGB7cn0NCg0KZGZfMTAgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCigid2l0aCBgcTFgIGFzIChTRUxFQ1QgYDIwMDdpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIEF2ZXJhZ2VJbmNvbWUsIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X291dHNpZGVfb2ZfaG91c2Vob2xkIGFzIE91dHNpZGVIb3VzZTIwMDcsIGAyMDA3aW5jb21lX2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZXMNCkZST00gYDIwMDdpbmNvbWVfY2xlYW5lZGANCkpPSU4gYDIwMDdpbnRlcm5ldF9jbGVhbmVkYCBPTiBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnJlZ2lvbiA9IGAyMDA3aW5jb21lX2NsZWFuZWRgLnJlZ2lvbikNCg0KU0VMRUNUIGBxMWAuU3RhdGVzLCBgcTFgLkF2ZXJhZ2VJbmNvbWUsIGBxMWAuT3V0c2lkZUhvdXNlMjAwNywNCkNBU0UgDQpXSEVOIGBxMWAuQXZlcmFnZUluY29tZSA8IDYwMDAwIFRIRU4gJ0xvdycNCldIRU4gYHExYC5BdmVyYWdlSW5jb21lID4gNzUwMDAgVEhFTiAnSGlnaCcNCkVMU0UgJ01lZGl1bScNCkVORCBBUyBJbmNvbWVCcmFja2V0cw0KRlJPTSBgcTFgIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KYGBgDQoNCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpBcyBzZWVuIGluIHRoZSBmb2xsb3dpbmcgZ3JhcGgsIHRoZSBtYXhpbXVtIGRpc2NyZXBhbmN5IGluIGludGVybmV0IGFjY2VzcyBvdXRzaWRlIHRoZSBob3VzZWhvbGQgZG9lcyBub3Qgc2VlbSB0byBjaGFuZ2UgYXMgaW5jb21lIGJyYWNrZXRzIGdvZXMgdXAuIFRoaXMgbWVhbnMgdGhhdCB0aGUgbWF4aW11bSB2YWx1ZSBvZiBhIHJlZ2lvbiB3aXRoIGludGVybmV0IGFjY2VzcyBvdXRzaWRlIHRoZSBob3VzZWhvbGQgbWludXMgdGhlIG1pbmltdW0gdmFsdWUgb2YgYSByZWdpb24gd2l0aCBpbnRlcm5ldCBhY2Nlc3Mgb3V0c2lkZSB0aGUgaG91c2Vob2xkIGluIGVhY2ggaW5jb21lIGJyYWNrZXQgc3RheXMgcmVsYXRpdmVseSB0aGUgc2FtZSBhcyBpbmNvbWUgYnJhY2tldHMgdHJhbnNpdGlvbiBmcm9tIGxvdyB0byBoaWdoLg0KDQpJIHNwZWNpZmljYWxseSBjaG9zZSBwZXJjZW50YWdlIG9mIHVzZXJzIHdpdGggaW50ZXJuZXQgYWNjZXNzIG91dHNpZGUgdGhlIGhvdXNlaG9sZCBhcyBJIGluaXRpYWxseSBoeXBvdGhlc2l6ZWQgdGhhdCBhZnRlciBhIGNlcnRhaW4gaW5jb21lIGxldmVsLCB0aGUgZGlzY3JlcGFuY3kgaW4gaW50ZXJuZXQgdXNhZ2Ugb3V0c2lkZSB0aGUgaG91c2Vob2xkIGFtb25nIHR3byBzdGF0ZXMgd291bGQgZ28gZG93bi4gSG93ZXZlciwgSSBmb3VuZCB0aGF0IHRoZXJlIHdhcyBubyByZWFsIGRpc2Nlcm5pYmxlIHJlbGF0aW9uc2hpcC4NCg0KVGhlIHZhbHVlcyBJIGNhbGN1bGF0ZWQgd2VyZSBhcyBmb2xsb3dzOg0KDQpNYXggQWNjZXNzIC0gTWluIEFjY2VzcyBWYWx1ZSA9IERpc2NyZXBlbmN5IGJ5IEluY29tZSBCcmFja2V0IExvdzogMTYuNyUgTWVkaXVtOiAxNi40JSBIaWdoOiAxNy4zJQ0KDQpCZWxvdyBpcyB0aGUgZ3JhcGggSSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGVzZSB2YWx1ZXMNCg0KYGBge3J9DQoNCkluY29tZUJyYWNrZXQ8LSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKQ0KTWF4RGlzY3JlcGVuY3kgPC0gYygiMTYuNyUiLCAiMTYuNCUiLCAiMTcuMyUiKQ0KZGZfMTE8LWRhdGEuZnJhbWUoSW5jb21lQnJhY2tldCwgTWF4RGlzY3JlcGVuY3kpDQoNCg0KcmVuZGVyRGF0YVRhYmxlKHsNCiAgRFQ6OmRhdGF0YWJsZShkZl8xMSwgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICBleHRlbnNpb25zID0gbGlzdChSZXNwb25zaXZlID0gVFJVRSwgRml4ZWRIZWFkZXIgPSBUUlVFKQ0KICApDQp9KQ0KDQoNCmRmXzEwYSA8LSBkZl8xMCAlPiUgZHBseXI6OmFycmFuZ2UoT3V0c2lkZUhvdXNlMjAwNykNCmRmXzEwYSRTdGF0ZXMgPC0gZmFjdG9yKGRmXzEwYSRTdGF0ZXMsIGxldmVscz1kZl8xMGEkU3RhdGVzKQ0KDQpyZW5kZXJQbG90KHtkZl8xMGEgJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHg9U3RhdGVzLCB5PU91dHNpZGVIb3VzZTIwMDcsIGNvbG9yID0gU3RhdGVzKSkgKyBnZW9tX3BvaW50KCkgKyBmYWNldF93cmFwKH5JbmNvbWVCcmFja2V0cykgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiSW50ZXJuZXQgVXNhZ2UgT3V0c2lkZSBIb3VzZSBieSBJbmNvbWUgQnJhY2tldCAoMjAwNykiLCB4PSJTdGF0ZSIsIHk9Ik91dHNpZGUgSG91c2UgVXNhZ2UiKX0pDQoNCmBgYA0KDQoqKiAgICoqDQojIyoqUGVyY2VudCBvZiBJbmRpdmlkdWFscyBXaG8gQWNjZXNzZWQgVGhlIEludGVybmV0IGZyb20gSG9tZSBpbiAyMDA3IGFuZCAyMDEyKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9Sc1d1MEZ0LnBuZykNCg0KYGBge3J9DQpkZjEgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbCgiU0VMRUNUIGAyMDEyaW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uIGFzIHJlZ2lvbixgMjAwN2ludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgYXMgMjAwNywgYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIGFzIDIwMTIgRlJPTSBgMjAwN2ludGVybmV0X2NsZWFuZWRgIExFRlQgSk9JTiBgMjAxMmludGVybmV0X2NsZWFuZWRgIE9OIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uID0gYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldCA9IHByb2plY3QpDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tLzBkVlN6Q2QucG5nKQ0KDQpgYGB7cn0NCmRmMWEgPC0gZGYxICU+JXRpZHlyOjpnYXRoZXIoIlllYXIiLCAiUGVyY2VudCIsCS0xKQ0KYGBgDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpBZnRlciB0aGUgZGF0YSB3YXMgam9pbmVkIEkgY2hvc2UgdG8gYW5hbHl6ZSB0aGUgcGVyY2VudCBvZiBpbmRpdmlkdWFscyB0aGF0IGFjY2Vzc2VkIHRoZSBpbnRlcm5ldCBmb3IgZWFjaCBzdGF0ZSBhbmQgY29tcGFyZSB0aGUgeWVhciAyMDA3IHRvIDIwMTIuIFRoZSBwbG90cyBiZWxvdyBpbGx1c3RyYXRlIHR3byBiYXIgY2hhcnRzIHRoYXQgc2hvdyB0aGUgcGVyY2VudCBvZiBpbmRpdmlkdWFscyB0aGF0IGFjY2Vzc2VkIHRoZSBpbnRlcm5ldCBmcm9tIGhvbWUgZm9yIGJvdGggeWVhcnMgYW5kIGFsc28gc2hvd3MgdGhlIGF2ZXJhZ2UgcGVyY2VudCBpbnRlcm5ldCB1c2FnZSBhY3Jvc3MgYWxsIHRoZSBzdGF0ZXMuIEZvciB0aGUgeWVhciAyMDA3IHRoZSBhdmVyYWdlIGludGVybmV0IHVzYWdlIHdhcyA2Ny4yMSUgcGVyY2VudCwgZm9yIHRoZSB5ZWFyIDIwMTIgdGhlIGF2ZXJhZ2UgaW50ZXJuZXQgdXNhZ2Ugd2FzIDY5Ljk5JS4gSXQgYXBwZWFycyB0aGF0IGludGVybmV0IHVzYWdlIGluY3JlYXNlZCBieSAyLjc4JSBvdmVyIGEgc3BhbiBvZiA1IHllYXJzLiBUaGlzIGlzIGxvd2VyIHRoYW4gd2hhdCBJIGV4cGVjdGVkIGJlY2F1c2UgbWFueSBuZXcgZGV2aWNlcyAoc3VjaCBhcyB0aGUgQXBwbGUgaVBhZCkgY2FtZSBvdXQgaW4gdGhhdCBmaXZlIHllYXIgcGVyaW9kIHRoYXQgc2hvdWxkIGhhdmUgYm9vc3RlZCBpbnRlcm5ldCB1c2FnZSBmcm9tIGhvbWUgYXQgYSBoaWdoZXIgcmF0ZS4NCg0KYGBge3J9DQoNCmlucHV0UGFuZWwoDQogIHNlbGVjdElucHV0KCJzZWxlY3RSZWdpb25kZjEiLCBsYWJlbCA9ICJTZWxlY3QgUmVnaW9uIiwNCiAgICAgICAgICAgICAgY2hvaWNlcyA9IGRmMSRyZWdpb24sIG11bHRpcGxlPVRSVUUsIHNlbGVjdGVkPWRmMSRyZWdpb24pDQopDQoNCnJlbmRlclBsb3Qoew0KZGYxYSAlPiUgZHBseXI6OmZpbHRlcihyZWdpb24gPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGYxLCAhZ3JlcGwoIi4qMTIkIiwgWWVhcikpICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSByZWdpb24sIHkgPSBQZXJjZW50KSxzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiUGVyY2VudCBvZiBJbmRpdmlkdWFscyB3aG8gQWNjZXNzZWQgSW50ZXJuZXQgRGF0YSBmcm9tIEhvbWUgaW4gMjAwNyIsIHg9IlJlZ2lvbiIsIHk9IlBlcmNlbnQiKQ0KfSkNCg0KcmVuZGVyUGxvdCh7DQpkZjFhICU+JSBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiLiowNyQiLCBZZWFyKSkgJT4lDQpnZ3Bsb3QoKSArIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IHJlZ2lvbiwgeSA9IFBlcmNlbnQpLHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiUGVyY2VudCBvZiBJbmRpdmlkdWFscyB3aG8gQWNjZXNzZWQgSW50ZXJuZXQgRGF0YSBmcm9tIEhvbWUgaW4gMjAxMiIsIHg9IlJlZ2lvbiIsIHk9IlBlcmNlbnQiKQ0KfSkNCg0KZGYxYiA8LSBkZjEgJT4lIGRwbHlyOjpzdW1tYXJpemUoYDIwMDdBdmdQZXJjZW50SW50ZXJuZXRVc2FnZWAgPSBtZWFuKGAyMDA3YCksIGAyMDEyQXZnUGVyY2VudEludGVybmV0VXNhZ2VgID0gbWVhbihgMjAxMmApKQ0KDQpyZW5kZXJEYXRhVGFibGUoew0KIERUOjpkYXRhdGFibGUoZGYxYiwgcm93bmFtZXMgPSBGQUxTRSwNCiBleHRlbnNpb25zID0gbGlzdChSZXNwb25zaXZlID0gVFJVRSwgRml4ZWRIZWFkZXIgPSBUUlVFKSkNCn0pDQogIA0KYGBgDQoNCioqICAgKioNCiMjICoqTGV2ZWxzIG9mIEludGVybmV0IFVzYWdlIGJ5IFN0YXRlIGFuZCBBdmVyYWdlIEluY29tZSBieSBTdGF0ZSBmb3IgdGhlIFllYXJzIDIwMDcvMjAxMioqDQoNCioqSW5wdXR0aW5nIHRoZSBDU1YgaW50byBSKioNCg0KUXVlcnlpbmcgdGhlIGRhdGEgZnJvbSB0aGUgMjAwNyBhbmQgMjAxMiBpbnRlcm5ldCBhY2Nlc3MgZGF0YSB0YWJsZXMgaGFzIGJlZW4gZG9uZSB0aGUgIlV0aWxpemluZyBkcGx5ciIiIHNlY3Rpb24gb2YgdGhpcyBpbnNpZ2h0IGJlY2F1c2UgaXQgbXVzdCBiZSBkb25lIHVuZGVyIHRoZSBldmVudFJlYWN0aXZlIGZ1bmN0aW9uLiBUaGUgcXVlcnkgZm9yIHRoZSBiYXJjaGFydHMgYW5hbHl6aW5nIHRoZSBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgZGF0YSBpcyBzaG93biBiZWxvdy4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vR0N0eUdvTi5wbmcpDQoNCmBgYHtyfQ0KZGYzYSA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsKCJTRUxFQ1QgYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uIGFzIHJlZ2lvbiwgYDIwMDdpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIDIwMDdBdmdIb3VzZWhvbGRJbmNvbWUsIA0KYDIwMTJpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIDIwMTJBdmdIb3VzZWhvbGRJbmNvbWUNCkZST00gYDIwMDdpbmNvbWVfY2xlYW5lZGAgSk9JTiBgMjAxMmluY29tZV9jbGVhbmVkYCBPTiBgMjAwN2luY29tZV9jbGVhbmVkYC5yZWdpb24gPSBgMjAxMmluY29tZV9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldCA9IHByb2plY3QpDQoNCmRmM2IgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbCgiU0VMRUNUIHJlZ2lvbiwgYDIwMDdpbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIGFzIDIwMDdBdmdIb3VzZWhvbGRJbmNvbWUgRlJPTSBgMjAwN2luY29tZV9jbGVhbmVkYCBXSEVSRSByZWdpb24gPSAnQWxhYmFtYScgT1IgcmVnaW9uID0gJ0xvdWlzaWFuYScgT1IgcmVnaW9uID0gJ01pc3Npc3NpcHBpJyBPUiByZWdpb24gPSAnVGV4YXMnIiksIGRhdGFzZXQgPSBwcm9qZWN0KQ0KDQpkZjNjIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwoIlNFTEVDVCByZWdpb24sIGAyMDEyaW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyAyMDEyQXZnSG91c2Vob2xkSW5jb21lIEZST00gYDIwMTJpbmNvbWVfY2xlYW5lZGAgV0hFUkUgcmVnaW9uID0gJ0FsYWJhbWEnIE9SIHJlZ2lvbiA9ICdMb3Vpc2lhbmEnIE9SIHJlZ2lvbiA9ICdNaXNzaXNzaXBwaScgT1IgcmVnaW9uID0gJ1RleGFzJyIpLCBkYXRhc2V0ID0gcHJvamVjdCkNCg0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpHYXRoZXJpbmcgaXMgbm90IG5lY2Vzc2FyeSBmb3IgdGhpcyBpbnNpZ2h0Lg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KVG8gZnVydGhlciBhbmFseXplIHRoZSBkYXRhIEkgam9pbmVkIGluIGEgcHJldmlvdXMgaW5zaWdodCwgSSBkZWNpZGVkIHRvIGNyZWF0ZSBhIG5ldyBkaXNjcmV0ZSB2YXJpYWJsZSB0aGF0IGxvb2tzIGF0IGxvdywgbWVkaXVtIGFuZCBoaWdoIGludGVybmV0IHVzYWdlLiBJIHF1ZXJpZWQgdGhlIGRhdGEgdXNpbmcgYSBDQVNFIHN0YXRlbWVudCB0byByZXBsaWNhdGUgdGhlIHBhcmFtZXRlcnMgYW5kIGNhbGN1bGF0ZWQgZmllbGQgSSBjcmVhdGVkIGluIFRhYmxlYXUuIFRoZSBxdWVyeSByZXN1bHRlZCBpbiBhIG5ldyBkaXNjcmV0ZSB2YXJpYWJsZSBzbyBJIGNvdWxkIGFuYWx5emUgbG93LCBtZWRpdW0gYW5kIGhpZ2ggdXNhZ2Ugb2YgdGhlIGludGVybmV0IGZyb20gaG9tZS4gVGhlIHBsb3QgYmVsb3cgc2hvd3MgdGhlIHJlc3VsdHMuDQoNCkZpbmFsbHkgSSBjcmVhdGVkIHR3byBjcm9zc3RhYnMgdG8gdmlzdWFsaXplIHRoZSBpbmZvcm1hdGlvbiBmb3IgYm90aCB5ZWFycy4gRm9yIGJvdGggeWVhcnMgaXQgYXBwZWFycyB0aGF0IE1pc3Npc3NpcHBpIGhhcyB0aGUgbG93ZXN0IHBlcmNlbnRhZ2Ugb2YgaW50ZXJuZXQgdXNhZ2UgaW4gdGhlIGNvdW50cnkgYW5kIE5ldyBIYW1wc2hpcmUgaGFzIHRoZSBoaWdoZXN0IGxldmVsIG9mIHVzYWdlLiBJbnRlcmVzdGluZ2x5LCBUZXhhcywgTG91aXNpYW5hLCBBbGFiYW1hLCBhbmQgTWlzc2lzc2lwcGkgYWxsIGZlbGwgdW5kZXIgdGhlIGxvdyB1c2FnZSBjYXRlZ29yeSBmb3IgYm90aCB5ZWFycy4gSXQgYXBwZWFycyB0aGF0IHNvdXRoZXJuIHN0YXRlcyBoYXZlIHRoZSBsb3dlc3QgbGV2ZWxzIG9mIGludGVybmV0IHVzYWdlLg0KDQpgYGB7cn0NCg0KaW5wdXRQYW5lbCgNCiAgc2VsZWN0SW5wdXQoInNlbGVjdFJlZ2lvbmRmMiIsIGxhYmVsID0gIlNlbGVjdCBSZWdpb24iLA0KICAgICAgICAgICAgICBjaG9pY2VzID0gZGYxJHJlZ2lvbiwgbXVsdGlwbGU9VFJVRSwgc2VsZWN0ZWQ9IGRmMSRyZWdpb24pDQopDQoNCmRmMmEgPC0gZXZlbnRSZWFjdGl2ZShjKGlucHV0JHNlbGVjdFJlZ2lvbmRmMiksIHsgDQogIHByb2plY3QgPC0gImh0dHBzOi8vZGF0YS53b3JsZC9hcGs1ODUvZi0xNy1lZHYtcHJvamVjdC01IiANCiAgZGF0YS53b3JsZDo6c2V0X2NvbmZpZyhjZmdfZW52KCJEV19BUEkiKSkgDQogIHBhcmFtUXVlcnkgPC0gZGF0YS53b3JsZDo6cXJ5X3NxbCgNCiAgICIgICANCndpdGggcTEgYXMgKFNFTEVDVCBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnJlZ2lvbiBhcyByZWdpb24sIGAyMDA3aW50ZXJuZXRfY2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSwNCkNBU0UNCldIRU4gYDIwMDdpbnRlcm5ldF9jbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIDwgNjIgVEhFTiAnTG93Jw0KV0hFTiBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgPj0gNzIgVEhFTiAnSGlnaCcNCkVMU0UgJ01lZGl1bScNCkVORCBhcyB1c2FnZV9sZXZlbA0KRlJPTSBgMjAwN2ludGVybmV0X2NsZWFuZWRgKQ0KDQpTRUxFQ1QgcGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBhcyBQZXJjZW50MjAwN0lBSG9tZSwgcmVnaW9uLCB1c2FnZV9sZXZlbA0KRlJPTSBxMQ0KDQogICAiKQ0KIHBhcmFtUXVlcnkkcGFyYW1zIDwtIGMoaW5wdXQkc2VsZWN0UmVnaW9uZGYyKQ0KIGRhdGEud29ybGQ6OnF1ZXJ5KHBhcmFtUXVlcnksIGRhdGFzZXQgPSBwcm9qZWN0KQ0KfSkgDQoNCnJlbmRlclBsb3Qoe2RmMmEoKSAlPiUgZHBseXI6OmZpbHRlcihyZWdpb24gPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGYyKSAlPiUgZ2dwbG90KCkgKyANCiAgZ2VvbV90ZXh0KGFlcyh4PXVzYWdlX2xldmVsLCB5PXJlZ2lvbiwgbGFiZWw9UGVyY2VudDIwMDdJQUhvbWUpLCBzaXplPTYpICsNCiAgZ2VvbV90aWxlKGFlcyh4PXVzYWdlX2xldmVsLCB5PXJlZ2lvbiwgZmlsbD11c2FnZV9sZXZlbCksIGFscGhhPTAuNTApICsNCiAgICB0aGVtZShsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCkpICsNCiAgICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjApLA0KICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhY2U9ImJvbGQiKSkgICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzAsIGZhY2UgPSAiYm9sZCIpKSArDQogICAgZ2d0aXRsZShwYXN0ZSgiUGVyY2VudCBvZiBJbmRpdmlkdWFscyB3aG8gQWNjZXNzZWQgSW50ZXJuZXQgRGF0YSBmcm9tIEhvbWUgaW4gMjAwNyIpKSArDQogIHhsYWIoIlVzYWdlIExldmVsIikgKyB5bGFiKCJSZWdpb24iKQ0KfSwgaGVpZ2h0ID0gNTAwLCB3aWR0aCA9IDEyMDApDQogIA0KDQpkZjJiIDwtIGV2ZW50UmVhY3RpdmUoYyhpbnB1dCRzZWxlY3RSZWdpb25kZjIpLCB7IA0KICBwcm9qZWN0IDwtICJodHRwczovL2RhdGEud29ybGQvYXBrNTg1L2YtMTctZWR2LXByb2plY3QtNSIgDQogIGRhdGEud29ybGQ6OnNldF9jb25maWcoY2ZnX2VudigiRFdfQVBJIikpIA0KICBwYXJhbVF1ZXJ5IDwtIGRhdGEud29ybGQ6OnFyeV9zcWwoDQogICAiU0VMRUNUIGAyMDEyaW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uIGFzIHJlZ2lvbiwgYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIGFzIFBlcmNlbnQyMDEySUFIb21lIEZST00gYDIwMTJpbnRlcm5ldF9jbGVhbmVkYCIpDQogIA0KIHBhcmFtUXVlcnkkcGFyYW1zIDwtIGMoaW5wdXQkc2VsZWN0UmVnaW9uZGYyKQ0KIGRhdGEud29ybGQ6OnF1ZXJ5KHBhcmFtUXVlcnksIGRhdGFzZXQgPSBwcm9qZWN0KQ0KfSkgDQoNCnJlbmRlclBsb3Qoe2RmMmIoKSAlPiUgZHBseXI6OmZpbHRlcihyZWdpb24gPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGYyKSAlPiUgZHBseXI6Om11dGF0ZSh1c2FnZV9sZXZlbCA9IGlmZWxzZShQZXJjZW50MjAxMklBSG9tZSA8IDYyLCAnTG93JywgaWZlbHNlKFBlcmNlbnQyMDEySUFIb21lID49IDcyLCAnSGlnaCcsICdNZWRpdW0nKSkpICU+JSBnZ3Bsb3QoKSArIA0KICBnZW9tX3RleHQoYWVzKHg9dXNhZ2VfbGV2ZWwsIHk9cmVnaW9uLCBsYWJlbD1QZXJjZW50MjAxMklBSG9tZSksIHNpemU9NikgKw0KICBnZW9tX3RpbGUoYWVzKHg9dXNhZ2VfbGV2ZWwsIHk9cmVnaW9uLCBmaWxsPXVzYWdlX2xldmVsKSwgYWxwaGE9MC41MCkgKw0KICAgIHRoZW1lKGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSkgKw0KICAgIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksDQogICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCwgZmFjZT0iYm9sZCIpKSAgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCwgZmFjZSA9ICJib2xkIikpICsNCiAgICBnZ3RpdGxlKHBhc3RlKCJQZXJjZW50IG9mIEluZGl2aWR1YWxzIHdobyBBY2Nlc3NlZCBJbnRlcm5ldCBEYXRhIGZyb20gSG9tZSBpbiAyMDEyIikpICsNCiAgeGxhYigiVXNhZ2UgTGV2ZWwiKSArIHlsYWIoIlJlZ2lvbiIpDQp9LCBoZWlnaHQgPSA1MDAsIHdpZHRoID0gMTIwMCkNCiAgDQpgYGANCg0KSSBkZWNpZGVkIHRvIGxvb2sgYXQgdGhlIGluY29tZSBsZXZlbHMgZm9yIHRoZSBzb3V0aGVybiBzdGF0ZXMgdGhhdCBoYXZlIHRoZSBsb3dlc3QgaW50ZXJuZXQgdXNhZ2Ugc28gSSBwZXJmb3JtZWQgYW4gaW5uZXIgam9pbiBvbiByZWdpb24gdG8gYnJpbmcgaW4gdGhlIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBmb3IgdGhlIHllYXJzIDIwMDcgYW5kIDIwMTIuDQoNClRoZSBwbG90cyBzaG93biBiZWxvdyBpbGx1c3RyYXRlIHRoZSBhdmVyYWdlIGluY29tZSBmb3IgaG91c2Vob2xkcyBieSBzdGF0ZS4gSW50ZXJlc3RpbmdseSwgdGhlIHN0YXRlcyB3aXRoIHRoZSBsb3dlc3QgYXZlcmFnZSBpbmNvbWUgYXBwZWFyIHRvIG92ZXJsYXAgd2l0aCB0aGUgc3RhdGVzIHRoYXQgaGF2ZSB0aGUgbG93ZXN0IGludGVybmV0IHVzYWdlIGxldmVscy4gU29tZSBmYW1pbGllcyBpbiB0aGVzZSBzb3V0aGVybiBzdGF0ZXMgbWF5IG5vdCBiZSBhYmxlIHRvIGFmZm9yZCBhbiBpbnRlcm5ldCBjb25uZWN0aW9uIGFuZCB0aGVyZWZvcmUgZG8gbm90IHVzZSB0aGUgaW50ZXJuZXQgYXQgaG9tZS4gSSBjcmVhdGVkIGEgc2V0IG9mIHRoZSBzb3V0aGVybiBzdGF0ZXMgdGhhdCBmZWxsIHVuZGVyIHRoZSBsb3cgY2F0ZWdvcnkgYW5kIGRpc3BsYXllZCB0aGVtLCB0aGUgYXZlcmFnZSBob3VzZWhvbGQgaW5jb21lIGZvciBhbGwgZm91ciBzdGF0ZXMgZmFsbCB1bmRlciB0aGUgbmF0aW9uYWwgYXZlcmFnZSBmb3IgdGhlIHllYXIgMjAwNyBhbmQgaW4gMjAxMiBBbGFiYW1hLCBNaXNzaXNzaXBwaSBhbmQgTG91aXNpYW5hIGZhbGwgdW5kZXIgdGhlIG5hdGlvbmFsIGF2ZXJhZ2UuDQoNCmBgYHtyfQ0KDQppbnB1dFBhbmVsKA0KICBzZWxlY3RJbnB1dCgic2VsZWN0UmVnaW9uZGYzIiwgbGFiZWwgPSAiU2VsZWN0IFJlZ2lvbiIsDQogICAgICAgICAgICAgIGNob2ljZXMgPSBkZjNhJHJlZ2lvbiwgbXVsdGlwbGU9VFJVRSwgc2VsZWN0ZWQ9ZGYzYSRyZWdpb24pDQopDQoNCnJlbmRlclBsb3Qoew0KZGYzYSAlPiUgZHBseXI6OmZpbHRlcihyZWdpb24gPT0gaW5wdXQkc2VsZWN0UmVnaW9uZGYzKSAlPiUgYXJyYW5nZShgMjAwN0F2Z0hvdXNlaG9sZEluY29tZWApICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSByZWdpb24sIHkgPSBgMjAwN0F2Z0hvdXNlaG9sZEluY29tZWApLHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIGJ5IFN0YXRlIDIwMDciLCB4PSJSZWdpb24iLCB5PSJJbmNvbWUiKQ0KfSkNCg0KcmVuZGVyUGxvdCh7DQpkZjNiICU+JSBnZ3Bsb3QoKSArDQogICAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcmVnaW9uLCB5ID0gYDIwMDdBdmdIb3VzZWhvbGRJbmNvbWVgLCBmaWxsID0gcmVnaW9uKSwgc3RhdCA9ICJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYnkgU3RhdGUgMjAwNyIsIHg9IlJlZ2lvbiIsIHk9IkluY29tZSIpDQp9KQ0KDQpyZW5kZXJQbG90KHsNCmRmM2EgJT4lIGRwbHlyOjpmaWx0ZXIocmVnaW9uID09IGlucHV0JHNlbGVjdFJlZ2lvbmRmMykgJT4lDQogICAgYXJyYW5nZShgMjAxMkF2Z0hvdXNlaG9sZEluY29tZWApICU+JQ0KZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSByZWdpb24sIHkgPSBgMjAxMkF2Z0hvdXNlaG9sZEluY29tZWApLHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIGJ5IFN0YXRlIDIwMTIiLCB4PSJSZWdpb24iLCB5PSJJbmNvbWUiKQ0KfSkNCg0KcmVuZGVyUGxvdCh7DQpkZjNjICU+JSBnZ3Bsb3QoKSArDQogICAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcmVnaW9uLCB5ID0gYDIwMTJBdmdIb3VzZWhvbGRJbmNvbWVgLCBmaWxsID0gcmVnaW9uKSwgc3RhdCA9ICJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYnkgU3RhdGUgMjAwNyIsIHg9IlJlZ2lvbiIsIHk9IkluY29tZSIpDQp9KQ0KDQogIA0KYGBgDQoNCioqICAgKioNCiMjICoqRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIGl0cyBSZWxhdGlvbnNoaXAgdG8gQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpJIGpvaW5lZCAyMDEyIEZhY2Vib29rIGRhdGEgd2l0aCAyMDEyIEluY29tZSBkYXRhIHVzaW5nIGFuIGlubmVyIGpvaW4gYXMgY2FuIGJlIHNlZW4gaW4gdGhlIHF1ZXJ5IGJlbG93Lg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS9uZXRNRkJJLnBuZykNCg0KYGBge3J9DQpkZjQgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbCgiU0VMRUNUIGZhY2Vib29rX2NsZWFuZWQuZmFjZWJvb2tfcGVuZXRyYXRpb24gYXMgRkJQZW5ldHJhdGlvbiwgZmFjZWJvb2tfY2xlYW5lZC5yZWdpb24gYXMgcmVnaW9uLCANCmAyMDEyaW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyBBdmdIb3VzZWhvbGRJbmNvbWUgRlJPTSBmYWNlYm9va19jbGVhbmVkIEpPSU4gYDIwMTJpbmNvbWVfY2xlYW5lZGAgT04gYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uID0gZmFjZWJvb2tfY2xlYW5lZC5yZWdpb24iKSwgZGF0YXNldCA9IHByb2plY3QpDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNCkdhdGhlcmluZyBpcyBub3QgbmVjZXNzYXJ5IGZvciB0aGlzIGluc2lnaHQuDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpMb29raW5nIGF0IHRoZSBGYWNlYm9vayBQZW5ldHJhdGlvbiBwZXJjZW50YWdlcyBpbiB0aGUgaGlzdG9ncmFtIGJlbG93LCBpdCBjYW4gYmUgc2VlbiB0aGF0IHRoZSBwZXJjZW50YWdlIG9mIEZhY2Vib29rIHVzYWdlIGZhbGxzIGJldHdlZW4gMzYlIGFuZCA0OCUgZm9yIGEgbWFqb3JpdHkgb2YgdGhlIHN0YXRlcy4gQSBmZXcgc3RhdGVzIGxpa2UgUmhvZGUgSXNsYW5kLCBJbGxpbm9pcyBhbmQgV2FzaGluZ3RvbiBzdGF0ZSB1c2UgRmFjZWJvb2sgYXQgYSBtdWNoIGhpZ2hlciBwZXJjZW50YWdlIHRoYW4gdGhlIHJlc3Qgb2YgdGhlIGNvdW50cnkuDQoNCmBgYHtyfQ0KcmVuZGVyUGxvdCh7DQogIGRmNCAlPiUgZHBseXI6OmZpbHRlcihyZWdpb24gIT0gIkRpc3RyaWN0IG9mIENvbHVtYmlhIikgJT4lIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0gRkJQZW5ldHJhdGlvbiwgZmlsbCA9IHJlZ2lvbiksIGJpbndpZHRoID0gMykgKyBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBGYWNlYm9vayBQZW5ldHJhdGlvbiIsIHg9IkZhY2Vib29rIFBlbmV0cmF0aW9uIFBlcmNlbnQiLCB5PSJDb3VudCIpDQp9KQ0KYGBgDQoNCkkgZGVjaWRlZCB0byB0ZXN0IHdoZXRoZXIgdGhlIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBoYWQgYW55dGhpbmcgdG8gZG8gd2l0aCBGYWNlYm9vayBwZW5ldHJhdGlvbiBwZXJjZW50YWdlcy4gSW4gYSBwcmV2aW91cyBpbnNpZ2h0IEkgZm91bmQgdGhhdCBzb3V0aGVybiBzdGF0ZXMgaGFkIHRoZSBsb3dlc3QgaW50ZXJuZXQgdXNhZ2UgYXQgaG9tZSBhbmQgdGhlIHNhbWUgc3RhdGVzIGhhZCBzb21lIG9mIHRoZSBsb3dlc3QgYXZlcmFnZXMgZm9yIGhvdXNlaG9sZCBpbmNvbWUuIFRoZXJlZm9yZSBJIGh5cG90aGVzaXplZCB0aGF0IEZhY2Vib29rIHVzYWdlIHdvdWxkIGJlIGhpZ2hlciBpbiBzdGF0ZXMgdGhhdCBoYXZlIGEgaGlnaGVyIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBhcyB3ZWxsIGJlY2F1c2Ugc29jaWFsIG1lZGlhIGlzIGEgY29tbW9uIHVzZSBvZiB0aGUgaW50ZXJuZXQuIEFjY29yZGluZyB0byB0aGUgcGxvdCwgRmFjZWJvb2sgcGVuZXRyYXRpb24gZ2VuZXJhbGx5IGFwcGVhcnMgdG8gaW5jcmVhc2UgYXMgdGhlIGF2ZXJhZ2UgaW5jb21lIGluY3JlYXNlcyBidXQgdGhlcmUgYXBwZWFycyB0byBiZSBubyBjbGVhciBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28uIFRoaXMgZ29lcyBhZ2FpbnN0IHdoYXQgSSBpbml0aWFsbHkgaHlwb3RoZXNpemVkIGJlY2F1c2UgSSBleHBlY3RlZCB0byBzZWUgaGlnaGVyIHNvY2lhbCBtZWRpYSB1c2FnZSBpbiBhcmVhcyB0aGF0IGFyZSBtb3JlIGFmZmx1ZW50Lg0KDQpJdCBhcHBlYXJzIHRoYXQgdGhlIHRocmVlIHN0YXRlcyB0aGF0IHVzZSBGYWNlYm9vayBhdCBhIGhpZ2hlciBwZXJjZW50YWdlIHRoYW4gdGhlIHJlc3Qgb2YgdGhlIGNvdW50cnkgKFJob2RlIElzbGFuZCwgSWxsaW5vaXMsIGFuZCBXYXNoaW5ndG9uIHN0YXRlKSBmYWxsIHNsaWdodGx5IGFib3ZlIHRoZSBhdmVyYWdlIEZhY2Vib29rIHBlbmV0cmF0aW9uIHBlcmNlbnRhZ2UgYW5kIHRoZSBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgZm9yIHRoZSBjb3VudHJ5IGJ1dCBhcmUgbm90IGFtb25nIHRoZSBzdGF0ZXMgd2l0aCB0aGUgaGlnaGVzdCBhdmVyYWdlIGluY29tZSBpbiB0aGUgY291bnRyeSBhcyBJIGh5cG90aGVzaXplZC4NCg0KYGBge3J9DQoNCnJlbmRlclBsb3Qoew0KICBkZjQgJT4lIGRwbHlyOjpmaWx0ZXIocmVnaW9uICE9ICJEaXN0cmljdCBvZiBDb2x1bWJpYSIpICU+JSBnZ3Bsb3QoKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gQXZnSG91c2Vob2xkSW5jb21lLCB5ID0gRkJQZW5ldHJhdGlvbiwgY29sb3IgPSByZWdpb24pKSArIGxhYnModGl0bGUgPSAiRmFjZWJvb2sgUGVuZXRyYXRpb24gdnMgQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIiwgeD0iQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIiwgeT0iRmFjZWJvb2sgUGVuZXRyYXRpb24iKQ0KfSkNCg0KDQpgYGANCg0KKiogICAqKg0KIyMgKipDb3JyZWxhdGlvbiBCZXR3ZWVuIEF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZSBhbmQgSW50ZXJuZXQgUGVuZXRyYXRpb24qKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkJhc2VkIG9uIHRoZSBjb25jbHVzaW9ucyBJIGFycml2ZWQgdG8gaW4gYSBwcmV2aW91cyBpbnNpZ2h0IGFib3V0IEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUsIEkgZGVjaWRlZCB0byB0YWtlIGl0IGEgc3RlcCBmdXJ0aGVyIGFuZCBsb29rIGF0IEludGVybmV0IFBlbmV0cmF0aW9uIHBlcmNlbnRhZ2VzIGluIGNvbXBhcmlzb24gdG8gdGhlIEF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZS4gQXMgY2FuIGJlIHNlZW4gaW4gdGhlIHF1ZXJ5IGJlbG93LCBJIGpvaW5lZCB0aGUgZGF0YSBvbiB0aGUgdmFyaWFibGUgInJlZ2lvbiIuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL3BaVTRaV0sucG5nKQ0KDQoNCk9uIHRhYmxlYXUgSSB2aXN1YWxpemVkIHRoZSBkYXRhIGJ5IGJsZW5kaW5nIGl0IGluc3RlYWQgb2Ygam9pbmluZyBpdCwgdGhlIHNjcmVlbnNob3QgYmVsb3cgZGVtb25zdHJhdGVzIGJsZW5kaW5nIHRoZSBkYXRhIGFuZCBlc3RhYmxpc2hpbmcgYSByZWxhdGlvbnNoaXAgb24gdGhlIGJhc2Ugb2YgdGhlIHZhcmlhYmxlICJyZWdpb24iIGluIGJvdGggZGF0YSBzZXRzLiBNb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBibGVuZGluZyBjYW4gYmUgZm91bmQgaW4gdGhlIGxpbmsgYXQgdGhlIGVuZCBvZiB0aGUgaW5zaWdodC4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vc3VJZGVQRi5wbmcpDQoNCmBgYHtyfQ0KZGY1IDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwoIlNFTEVDVCBgMjAxMmluY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUgYXMgQXZnSW5jb21lLCBmYWNlYm9va19jbGVhbmVkLnJlZ2lvbiBhcyByZWdpb24sIGZhY2Vib29rX2NsZWFuZWQuaW50ZXJuZXRfcGVuZXRyYXRpb24gYXMgSW50ZXJuZXRQZW5ldHJhdGlvbg0KRlJPTSBgMjAxMmluY29tZV9jbGVhbmVkYEpPSU4gZmFjZWJvb2tfY2xlYW5lZCBPTiBgMjAxMmluY29tZV9jbGVhbmVkYC5yZWdpb24gPSBmYWNlYm9va19jbGVhbmVkLnJlZ2lvbiIpLCBkYXRhc2V0ID0gcHJvamVjdCkNCmBgYA0KDQoqKlJlZm9ybWF0dGluZyBpbiBSKioNCg0KR2F0aGVyaW5nIGlzIG5vdCBuZWNlc3NhcnkgZm9yIHRoaXMgaW5zaWdodC4NCg0KKipVdGlsaXppbmcgZHBseXIgdG8gdHJhbnNmb3JtLCB2aXN1YWxpemUsIGFuZCBjb21tdW5pY2F0ZSoqDQoNCkkgcGxvdHRlZCBpbnRlcm5ldCBwZW5ldHJhdGlvbiBwZXJjZW50YWdlcyBhZ2FpbnN0IHRoZSBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgZGF0YS4gQXMgY2FuIGJlIHNlZW4gaW4gdGhlIHNjYXR0ZXJwbG90IGJlbG93LCBhdCBsZWFzdCA1MCUgb2YgdGhlIHBvcHVsYXRpb24gdXNlcyB0aGUgaW50ZXJuZXQgaW4gZXZlcnkgc3RhdGUuIEEgZ2VuZXJhbCB0cmVuZCBsaW5lIHNob3dzIHRoYXQgYXMgdGhlIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBpbmNyZWFzZXMsIHRoZSBwZXJjZW50IG9mIGludGVybmV0IHBlbmV0cmF0aW9uIGluY3JlYXNlcyBhcyB3ZWxsLg0KDQpgYGB7cn0NCnJlbmRlclBsb3Qoew0KICBkZjUgJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBBdmdJbmNvbWUsIHkgPSBJbnRlcm5ldFBlbmV0cmF0aW9uKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIiwgeD0iQXZlcmFnZSBJbmNvbWUiLCB5PSJJbnRlcm5ldCBQZW5ldHJhdGlvbiIpDQp9KQ0KYGBgDQoNCkFuIG91dGxpZXIgaW4gdGhlIGRhdGEgaXMgdGhlIERpc3RyaWN0IG9mIENvbHVtYmlhIHdoaWNoIGhhcyB0aGUgaGlnaGVzdCBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgaW4gdGhlIGNvdW50cnkgYnV0IGZhbGxzIGJlbG93IHRoZSBhdmVyYWdlIGZvciBpbnRlcm5ldCBwZW5ldHJhdGlvbiBwZXJjZW50YWdlLiBUbyBzZWUgd2hlcmUgREMgZmFsbHMgY29tcGFyZWQgdG8gdGhlIHJlc3Qgb2YgdGhlIGNvdW50cnkgd2hlbiBpdCBjb21lcyB0byBpbnRlcm5ldCBwZW5ldHJhdGlvbiBwZXJjZW50YWdlcywgSSBjYWxjdWxhdGVkIHRoZSBwZXJjZW50IHJhbmsgZm9yIGVhY2ggc3RhdGUgaW4gdGhlIG11dGF0ZSBmdW5jdGlvbi4gSSBwbG90dGVkIHRoZSBzdGF0ZSByYW5raW5ncyBhZ2FpbnN0IHRoZSBzdGF0ZXMgdG8gc2VlIGhvdyB0aGV5IGZlbGwgaW4gdGhlIHJhbmdlIGJldHdlZW4gMCBhbmQgMS4gSXQgYXBwZWFycyB0aGF0IEQuQy4gaXMgcmFua2VkIC4zNiB3aGljaCBpcyBmYWlybHkgbG93IGZvciB0aGUgbmF0aW9uJ3MgY2FwaXRhbCBhbmQgY2VudGVyIG9mIGdvdmVybm1lbnQgb3BlcmF0aW9ucy4gQWRkaXRpb25hbGx5LCBjb25zaWRlcmluZyB0aGF0IGl0IGlzIGhhcyB0aGUgaGlnaGVzdCBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgaW4gdGhlIG5hdGlvbiwgdGhpcyBpcyBhbiBpbnRlcmVzdGluZ2x5IGxvdyByYW5raW5nIGZvciBELkMuDQoNCmBgYHtyfQ0KcmVuZGVyUGxvdCh7DQogIGRmNSAlPiUgZHBseXI6Om11dGF0ZShSYW5rID0gcGVyY2VudF9yYW5rKEludGVybmV0UGVuZXRyYXRpb24pKSAlPiUgZHBseXI6OmFycmFuZ2UoUmFuaykgJT4lIGdncGxvdCgpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSByZWdpb24sIHkgPSBSYW5rKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArIGxhYnModGl0bGUgPSAiUGVyY2VudGlsZSBSYW5raW5ncyBvZiBJbnRlcm5ldCBVc2FnZSBieSBTdGF0ZSIsIHg9IlJlZ2lvbiIsIHk9IlJhbmsiKQ0KfSkNCg0KYGBgDQoNCioqICAgKioNCiMjICoqRGlmZmVyZW5jZSBpbiBJbmNvbWUgYnkgU3RhdGUgZm9yIDIwMDctMjAxMioqDQoNCioqSW5wdXR0aW5nIHRoZSBDU1YgaW50byBSKioNCg0KRm9yIHRoZSBmb2xsb3dpbmcgaW5zaWdodCBJIGZ1bGwgam9pbmVkIHRoZSBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgZGF0YSBmb3IgdGhlIHllYXJzIDIwMDcgYW5kIDIwMTIgb24gdGhlIHZhcmlhYmxlICJyZWdpb24uIg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS90N2pHWkY3LnBuZykNCg0KYGBge3J9DQpkZjYgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbCgiU0VMRUNUIGAyMDEyaW5jb21lX2NsZWFuZWRgLnJlZ2lvbiBhcyByZWdpb24sIGAyMDEyaW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyAyMDEyLCBgMjAwN2luY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUgYXMgMjAwNw0KRlJPTSBgMjAwN2luY29tZV9jbGVhbmVkYCBGVUxMIEpPSU4gYDIwMTJpbmNvbWVfY2xlYW5lZGAgT04gYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uID0gYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQgPSBwcm9qZWN0KQ0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQohW10oaHR0cHM6Ly9pLmltZ3VyLmNvbS8yRHRaODdzLnBuZykNCg0KYGBge3J9DQpkZjZhIDwtIGRmNiAlPiV0aWR5cjo6Z2F0aGVyKCJZZWFyIiwgIkF2ZXJhZ2VJbmNvbWUiLAktMSkNCmBgYA0KDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpJIGNyZWF0ZWQgYSBmYWNldC13cmFwcGVkIGJhciBjaGFydCB0aGF0IGRpc3BsYXlzIHRoZSBhdmVyYWdlIGhvdXNlaG9sZCBpbmNvbWUgZm9yIGVhY2ggeWVhciBieSByZWdpb24uIEJ5IGxvb2tpbmcgYXQgdGhpcyBiYXIgY2hhcnQgYWxvbmUgaXQgaXMgZGlmZmljdWx0IHRvIGV4dHJhcG9sYXRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkaWZmZXJlbmNlIGluIGluY29tZSBmb3IgZWFjaCBzdGF0ZSBpbiB0aGlzIGZpdmUgeWVhciBwZXJpb2QuIFRvIGdldCBhcm91bmQgdGhpcyBpc3N1ZSBpbiBUYWJsZWF1IEkgY3JlYXRlZCBhIGxldmVsIG9mIGRldGFpbCBleHByZXNzaW9uIHRoYXQgY2FsY3VsYXRlcyB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgaW5jb21lIGJldHdlZW4gdGhlIHllYXJzIDIwMDcgYW5kIDIwMTIgZm9yIGVhY2ggc3RhdGUuIFRoZSBzY3JlZW5zaG90IGRpc3BsYXlpbmcgdGhpcyBpcyBiZWxvdy4gSW4gUiB0aGUgZGlmZmVyZW5jZSB3YXMgY2FsY3VsYXRlZCB1c2luZyB0aGUgbGFnIGZ1bmN0aW9uIHdpdGhpbiBkcGx5ciBtdXRhdGUuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL3QwZXZQcloucG5nKQ0KDQpgYGB7cn0NCg0KcmVuZGVyUGxvdCh7DQpkZjZhICU+JSBkcGx5cjo6c2VsZWN0KHJlZ2lvbiwgWWVhciwgQXZlcmFnZUluY29tZSkgJT4lIA0KICAgIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcmVnaW9uLCB5ID0gQXZlcmFnZUluY29tZSksIHN0YXQgPSAnaWRlbnRpdHknKSArIGZhY2V0X3dyYXAoflllYXIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKyBsYWJzKHRpdGxlID0gIkEgQ29tcGFyaXNvbiBvZiBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgZm9yIDIwMDcgJiAyMDEyIiwgeD0iUmVnaW9uIiwgeT0iQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIikNCiAgDQp9KQ0KDQpkZjZiIDwtIGRmNmEgJT4lIGRwbHlyOjpncm91cF9ieShyZWdpb24pICU+JSBtdXRhdGUoRGlmZmVyZW5jZUluY29tZSA9IGxhZyhBdmVyYWdlSW5jb21lKSAtIEF2ZXJhZ2VJbmNvbWUpICU+JSBkcGx5cjo6ZmlsdGVyKFllYXIgPT0gIjIwMDciKQ0KDQpgYGANCg0KQXMgY2FuIGJlIHNlZW4gaW4gdGhlIGJveCBwbG90IGJlbG93LCBvdmVyIDkwJSBvZiB0aGUgc3RhdGVzIGhhZCBhIHBvc2l0aXZlIGRpZmZlcmVuY2UgaW4gaW5jb21lIGluZGljYXRpbmcgdGhhdCB0aGUgYXZlcmFnZSBob3VzZWhvbGQgaW5jb21lIGluY3JlYXNlZC4gVGhpcyBjb3VsZCBiZSBkdWUgdG8gc2V2ZXJhbCBmYWN0b3JzIChpbmZsYXRpb24sIGNoYW5nZXMgaW4gbG9jYWwvc3RhdGUgdGF4ZXMsIGV0YykuIFRoZSBzdGF0ZSB3aXRoIHRoZSBoaWdoZXN0IGRpZmZlcmVuY2UgaW4gaW5jb21lIHdhcyBOb3J0aCBEYWtvdGEgd2l0aCBhIGRpZmZlcmVuY2Ugb2YgMTYgdGhvdXNhbmQgZG9sbGFycy4gTm9ydGggRGFrb3RhIGlzIGZvbGxvd2VkIGJ5IEQuQy4gd2hpY2ggaGFkIGFuIGluY29tZSBpbmNyZWFzZSBvZiAxMyB0aG91c2FuZC4gQm90aCBvZiB0aGVzZSBzdGF0ZXMgYXJlIG91dGxpZXJzIGluIHRoZSBkYXRhIHNldC4gVGhlIHN0YXRlIHdpdGggdGhlIGxhcmdlc3QgbmVnYXRpdmUgZGlmZmVyZW5jZSB3YXMgTmV2YWRhLCB0aGUgYXZlcmFnZSBpbmNvbWUgb2Ygd2hpY2ggZHJvcHBlZCBieSA2IHRob3VzYW5kIGRvbGxhcnMgZnJvbSAyMDA3IHRvIDIwMTIuDQoNCmBgYHtyfQ0KDQpyZW5kZXJQbG90KHsNCmRmNmIgJT4lIGdncGxvdCgpICsgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsIHkgPSBEaWZmZXJlbmNlSW5jb21lKSkgKyBsYWJzKHRpdGxlID0gIkRpZmZlcmVuY2UgaW4gQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIDIwMDcvMjAxMiIsIHg9IiIsIHk9IkRpZmZlcmVuY2UgaW4gSW5jb21lIikNCn0pDQoNCmBgYA0KDQpUbyBsb29rIGF0IHRoZSByZXN0IG9mIHRoZSBzdGF0ZXMgYnkgcmVtb3ZpbmcgdGhlc2Ugb3V0bGllcnMsIEkgY3JlYXRlZCBhIG1hcCB1c2luZyBhIGNvbG9yIGdyYWRpZW50IHRvIHNob3cgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGF2ZXJhZ2UgaW5jb21lLiBJIHJlbW92ZWQgdGhlIHRocmVlIG91dGxpZXJzIGFuZCBmb3VuZCB0aGF0IFNvdXRoIERha290YSBoYWQgdGhlIGxhcmdlc3QgcG9zaXRpdmUgZGlmZmVyZW5jZSBpbmNvbWUgYW5kIEZsb3JpZGEgaGFkIHRoZSBsYXJnZXN0IG5lZ2F0aXZlIGRpZmZlcmVuY2UuIE9ubHkgZm91ciBzdGF0ZXMgaGFkIGEgbmVnYXRpdmUgY2hhbmdlIGluIGF2ZXJhZ2UgaW5jb21lIGFuZCB0aGVzZSBzdGF0ZXMgd2VyZSBGbG9yaWRhLCBJZGFobywgQXJpem9uYSBhbmQgR2VvcmdpYS4NCg0KYGBge3J9DQoNCmRmNmMgPC0gZGY2YiAlPiUgZHBseXI6OnNlbGVjdChyZWdpb24sIERpZmZlcmVuY2VJbmNvbWUpICU+JSBkcGx5cjo6ZmlsdGVyKHJlZ2lvbiAhPSAiTm9ydGggRGFrb3RhIiwgcmVnaW9uICE9ICJOZXZhZGEiLCByZWdpb24gIT0gIkRpc3RyaWN0IG9mIENvbHVtYmlhIikNCg0KbmFtZXMoZGY2YykgPC0gYygicmVnaW9uIiwidmFsdWUiKQ0KZGY2YyRyZWdpb24gPC0gdG9sb3dlcihkZjZjJHJlZ2lvbikNCmRmNmMkcmVnaW9uIDwtIGdzdWIoIiAodS5zLiBzdGF0ZSIsICIiLCBkZjZjJHJlZ2lvbiwgZml4ZWQgPSBUUlVFKQ0KcmVuZGVyUGxvdCh7c3RhdGVfY2hvcm9wbGV0aChkZjZjKX0pDQogIA0KYGBgDQoqKiAgICoqDQojIyAqKkludGVybmV0IFVzYWdlIGF0IEhvbWUgYW5kIGl0cyBDb3JyZWxhdGlvbiB3aXRoIHRoZSA2NS02OSBZZWFyIE9sZCBQb3B1bGF0aW9uKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpGb3IgdGhlIGZvbGxvd2luZyBpbnNpZ2h0IEkgaW5uZXIgam9pbmVkIGZvdXIgZGF0YSBmcmFtZXMsIHBvcHVsYXRpb24gZmlndXJlcyBmb3IgMjAwNyBhbmQgMjAxMiBhbmQgaW50ZXJuZXQgdXNhZ2UgZmlndXJlcyBmb3IgMjAwNyBhbmQgMjAxMi4NCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vYkxFamJnbS5wbmcpDQoNCmBgYHtyfQ0KZGY3IDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwoIlNFTEVDVCBgMjAwN3BvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uIGFzIHJlZ2lvbiwgDQpgMjAwN2ludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgYXMgUGVyY2VudElBSG9tZSwgDQpgMjAwN3BvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfZXN0aW1hdGVfdG90YWxfcG9wdWxhdGlvbl9hZ2VfNjVfdG9fNjlfeWVhcnMgYXMgUGVyY2VudDY1dG82OVBvcCwgYDIwMDdwb3B1bGF0aW9uX2NsZWFuZWRgLnRvdGFsX2VzdGltYXRlX3RvdGFsX3BvcHVsYXRpb25fYWdlXzMwX3RvXzM0X3llYXJzIGFzIFBlcmNlbnQzMHRvMzRQb3ANCkZST00gYDIwMDdpbnRlcm5ldF9jbGVhbmVkYCBKT0lOIGAyMDA3cG9wdWxhdGlvbl9jbGVhbmVkYCBPTiBgMjAwN2ludGVybmV0X2NsZWFuZWRgLnJlZ2lvbiA9IGAyMDA3cG9wdWxhdGlvbl9jbGVhbmVkYC5yZWdpb24iKSwgZGF0YXNldCA9IHByb2plY3QpDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNCkdhdGhlcmluZyBpcyBub3QgbmVjZXNzYXJ5IGZvciB0aGlzIGluc2lnaHQuDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpPbiB0YWJsZWF1LCBJIGNyZWF0ZWQgYSBkYXNoYm9hcmQgZGlzcGxheWluZyB0d28gcGFja2VkIGJ1YmJsZXMgcGxvdHMuIEZvciB0aGUgcm1kIEkgY3JlYXRlZCBhIG1hcCBpbnN0ZWFkLCBidXQgSSBwcm92aWRlZCBhIHNjcmVlbnNob3Qgb2YgdGhlIHBhY2tlZCBidWJibGVzIHBsb3QgYW5kIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgaXQgY2FuIGJlIGZvdW5kIGluIHRoZSBsaW5rIGF0IHRoZSBlbmQgb2YgdGhpcyBpbnNpZ2h0LiANCg0KIVtdKGh0dHBzOi8vaS5pbWd1ci5jb20vcEVxeFplay5wbmcpDQoNCg0KVGhlIGZpcnN0IG1hcCBkaXNwbGF5cyBpbnRlcm5ldCB1c2FnZSBhdCBob21lIGJ5IHN0YXRlIGZvciB0aGUgeWVhciAyMDA3LCB0aGUgc2Vjb25kIGRpc3BsYXlzIHRoZSBwb3B1bGF0aW9uIHBlcmNlbnQgb2YgNjUtNjkgeWVhciBvbGRzIGJ5IHN0YXRlLiBJIHdhbnRlZCB0byBsb29rIGF0IGhvdyB0aGUgcG9wdWxhdGlvbiBwZXJjZW50IG9mIHRoZSA2NS02OSB5ZWFyIG9sZHMgY29tcGFyZXMgdG8gdGhlIHBlcmNlbnQgb2YgcGVvcGxlIHVzaW5nIHRoZSBpbnRlcm5ldCBhdCBob21lLiBCYXNlZCBvbiB0aGUgcGxvdHMgaXQgYXBwZWFycyB0aGF0IHRoZSB0d28gc3RhdGVzIChVdGFoIGFuZCBBbGFza2EpIHRoYXQgaGF2ZSB0aGUgaGlnaGVzdCBwZXJjZW50IG9mIGludGVybmV0IHVzYWdlIGF0IGhvbWUgYWxzbyBoYXZlIHRoZSBsb3dlc3QgcGVyY2VudCBvZiA2NS02OSB5ZWFyIG9sZHMuIFRoZSBvcHBvc2l0ZSBzZWVtcyB0byBob2xkIHRydWUgYXMgd2VsbCwgYXMgV2VzdCBWaXJnaW5pYSBpcyBvbmUgb2YgdGhlIHN0YXRlcyB3aXRoIHRoZSBsb3dlc3QgcGVyY2VudGFnZSBvZiBpbnRlcm5ldCB1c2FnZSBhbmQgaXQgaGFzIHRoZSBoaWdoZXN0IHBlcmNlbnQgb2YgNjUtNjkgeWVhciBvbGRzIGluIHRoZSBjb3VudHJ5Lg0KDQpUaGlzIGdlbmVyYWwgdHJlbmQgbWFrZXMgc2Vuc2UgYXMgb2xkZXIgcGVvcGxlIGFyZSBsZXNzIGxpa2VseSB0byB1c2UgdGhlIGludGVybmV0IGFzIG9mdGVuIGFzIHlvdW5nZXIgcGVvcGxlLiBJIGRlY2lkZWQgdG8gY29tcGFyZSBpbnRlcm5ldCB1c2FnZSBwZXJjZW50YWdlcyBhZ2FpbnN0IHRoZSBwb3B1bGF0aW9uIHBlcmNlbnRhZ2VzIG9mIDMwLTM0IHllYXIgb2xkcyBieSBzdGF0ZSBhcyB3ZWxsIHRvIGNvbmZpcm0gbXkgaHlwb3RoZXNpcy4gQmFzZWQgb24gdGhlIG1hcHMgc2hvd24gYmVsb3cgdGhlIHN0YXRlcyB0aGF0IGhhdmUgYSBoaWdoIHBlcmNlbnQgb2YgaW50ZXJuZXQgdXNhZ2UgYXQgaG9tZSBoYXZlIGEgbXVjaCBoaWdoZXIgcGVyY2VudCBvZiAzMC0zNCB5ZWFyIG9sZHMgdGhhbiB0aGV5IGRvIDY1LTY5IHllYXIgb2xkcy4NCg0KYGBge3J9DQoNCmRmN2EgPC0gZGY3ICU+JSBkcGx5cjo6c2VsZWN0KHJlZ2lvbiwgUGVyY2VudElBSG9tZSkNCmRmN2IgPC0gZGY3ICU+JSBkcGx5cjo6c2VsZWN0KHJlZ2lvbiwgUGVyY2VudDY1dG82OVBvcCkNCmRmN2MgPC0gZGY3ICU+JSBkcGx5cjo6c2VsZWN0KHJlZ2lvbiwgUGVyY2VudDMwdG8zNFBvcCkNCg0KbmFtZXMoZGY3YSkgPC0gYygicmVnaW9uIiwidmFsdWUiKQ0KZGY3YSRyZWdpb24gPC0gdG9sb3dlcihkZjdhJHJlZ2lvbikNCmRmN2EkcmVnaW9uIDwtIGdzdWIoIiAodS5zLiBzdGF0ZSIsICIiLCBkZjdhJHJlZ2lvbiwgZml4ZWQgPSBUUlVFKQ0KcmVuZGVyUGxvdCh7c3RhdGVfY2hvcm9wbGV0aChkZjdhKX0pDQoNCm5hbWVzKGRmN2IpIDwtIGMoInJlZ2lvbiIsInZhbHVlIikNCmRmN2IkcmVnaW9uIDwtIHRvbG93ZXIoZGY3YiRyZWdpb24pDQpkZjdiJHJlZ2lvbiA8LSBnc3ViKCIgKHUucy4gc3RhdGUiLCAiIiwgZGY3YiRyZWdpb24sIGZpeGVkID0gVFJVRSkNCnJlbmRlclBsb3Qoe3N0YXRlX2Nob3JvcGxldGgoZGY3Yil9KQ0KYGBgDQoNClRoaXMgZ2VuZXJhbCB0cmVuZCBtYWtlcyBzZW5zZSBhcyBvbGRlciBwZW9wbGUgYXJlIGxlc3MgbGlrZWx5IHRvIHVzZSB0aGUgaW50ZXJuZXQgYXMgb2Z0ZW4gYXMgeW91bmdlciBwZW9wbGUuIEkgZGVjaWRlZCB0byBjb21wYXJlIGludGVybmV0IHVzYWdlIHBlcmNlbnRhZ2VzIGFnYWluc3QgdGhlIHBvcHVsYXRpb24gcGVyY2VudGFnZXMgb2YgMzAtMzQgeWVhciBvbGRzIGJ5IHN0YXRlIGFzIHdlbGwgdG8gY29uZmlybSBteSBoeXBvdGhlc2lzLiBCYXNlZCBvbiB0aGUgbWFwcyBzaG93biBiZWxvdyB0aGUgc3RhdGVzIHRoYXQgaGF2ZSBhIGhpZ2ggcGVyY2VudCBvZiBpbnRlcm5ldCB1c2FnZSBhdCBob21lIGhhdmUgYSBtdWNoIGhpZ2hlciBwZXJjZW50IG9mIDMwLTM0IHllYXIgb2xkcyB0aGFuIHRoZXkgZG8gNjUtNjkgeWVhciBvbGRzLg0KDQpgYGB7cn0NCm5hbWVzKGRmN2MpIDwtIGMoInJlZ2lvbiIsInZhbHVlIikNCmRmN2MkcmVnaW9uIDwtIHRvbG93ZXIoZGY3YyRyZWdpb24pDQpkZjdjJHJlZ2lvbiA8LSBnc3ViKCIgKHUucy4gc3RhdGUiLCAiIiwgZGY3YyRyZWdpb24sIGZpeGVkID0gVFJVRSkNCnJlbmRlclBsb3Qoe3N0YXRlX2Nob3JvcGxldGgoZGY3Yyl9KQ0KYGBgDQoNCg0KKiogICAqKg0KIyMgKipGYWNlYm9vayBQZW5ldHJhdGlvbiBmb3IgMTUtMTkgWWVhciBPbGRzIFZlcnN1cyA0MC00NCBZZWFyIE9sZHMqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkkgZGVjaWRlZCB0byBqb2luIDIwMTIgRmFjZWJvb2sgZGF0YSB3aXRoIDIwMTIgUG9wdWxhdGlvbiBkYXRhIHRvIGNvbXBhcmUgdGhlIHBlcmNlbnQgb2YgeW91bmdlciBwZW9wbGUgdG8gbWlkZGxlIGFnZWQgYWR1bHRzIGluIHJlZ2lvbnMgdGhhdCBoYXZlIGEgaGlnaGVyIEZhY2Vib29rIHBlbmV0cmF0aW9uIHBlcmNlbnRhZ2UuDQoNCiFbXShodHRwczovL2kuaW1ndXIuY29tL1E5ZmdRWnAucG5nKQ0KDQpgYGB7cn0NCmRmOCA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsKCJTRUxFQ1QgYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiBhcyByZWdpb24sIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9lc3RpbWF0ZV9hZ2VfMTVfdG9fMTlfeWVhcnMgYXMgUGVyY2VudDE1dG8xOVBvcHVsYXRpb24sIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9lc3RpbWF0ZV9hZ2VfNDBfdG9fNDRfeWVhcnMgYXMgUGVyY2VudDQwdG80NFBvcHVsYXRpb24sIGZhY2Vib29rX2NsZWFuZWQuZmFjZWJvb2tfcGVuZXRyYXRpb24gYXMgRkJQZW5ldHJhdGlvbiBGUk9NIGZhY2Vib29rX2NsZWFuZWQgSk9JTiBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAgT04gZmFjZWJvb2tfY2xlYW5lZC5yZWdpb24gPSBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQgPSBwcm9qZWN0KQ0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpHYXRoZXJpbmcgaXMgbm90IG5lY2Vzc2FyeSBmb3IgdGhpcyBpbnNpZ2h0Lg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KU29jaWFsIG1lZGlhIGlzIGdlbmVyYWxseSBhIHlvdW5nIHBlcnNvbidzIHBhc3MtdGltZSBidXQgaW4gcmVjZW50IHllYXJzIHRoZXJlIGhhcyBiZWVuIGEgc3VyZ2Ugb2YgbWlkZGxlIGFnZWQgdXNlcnMgY3JlYXRpbmcgYWNjb3VudHMgb24gb3V0bGV0cyBsaWtlIEZhY2Vib29rLiBJbiBzb21lIHJlZ2lvbnMgdGhlIHBlcmNlbnQgb2YgbWlkZGxlIGFnZWQgYWR1bHRzIG1heSBldmVuIGV4Y2VlZCB0aGUgcG9wdWxhdGlvbiBvZiB5b3VuZ2VyIGFkdWx0cy4NCg0KSSBpc29sYXRlZCB0aHJlZSBzdGF0ZXMgd2l0aCBhIGhpZ2ggRmFjZWJvb2sgcGVuZXRyYXRpb24gcGVyY2VudGFnZS4gQXMgY2FuIGJlIHNlZW4gaW4gdGhlIHBsb3RzIGJlbG93LCB0aGUgc3RhdGUgb2YgV2FzaGluZ3RvbiBoYXMgYSB2ZXJ5IGhpZ2ggRmFjZWJvb2sgcGVuZXRyYXRpb24gcGVyY2VudGFnZS4gVGhlIHBlcmNlbnQgb2YgMTUtMTkgeWVhciBvbGRzIGluIHRoZSBzdGF0ZSBpcyA2LjUlIHdoaWxlIHRoZSBwZXJjZW50IG9mIDQwLTQ0IHllYXIgb2xkcyBpcyBoaWdoZXIgYXQgNi44JS4gTmV3IEplcnNleSwgYW5vdGhlciBzdGF0ZSB3aXRoIGEgaGlnaCBGYWNlYm9vayBwZW5ldHJhdGlvbiBwZXJjZW50YWdlLCBoYXMgNi42JSAxNS0xOSB5ZWFyIG9sZHMgYW5kIDcuMiUgNDAtNDQgeWVhciBvbGRzLiBMYXN0bHksIEFsYXNrYSBoYXMgNi44JSAxNS0xOSB5ZWFyIG9sZHMgYW5kIDYuOSUgNDAtNDQgeWVhciBvbGRzLiBBcyBoeXBvdGhlc2l6ZWQsIHRoZSBwZXJjZW50IG9mIG1pZGRsZSBhZ2VkIGFkdWx0cyBpbmRlZWQgZXhjZWVkcyB0aGUgcG9wdWxhdGlvbiBvZiB5b3VuZ2VyIGFkdWx0cy4NCg0KYGBge3J9DQoNCnJlbmRlclBsb3Qoe2RmOCAlPiUgZHBseXI6OnNlbGVjdChyZWdpb24sIEZCUGVuZXRyYXRpb24pICU+JSBkcGx5cjo6ZmlsdGVyKHJlZ2lvbiAlaW4lIGMoIldhc2hpbmd0b24iLCAiQWxhc2thIiwgIk5ldyBKZXJzZXkiKSkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcmVnaW9uLCB5ID0gRkJQZW5ldHJhdGlvbiwgZmlsbCA9IHJlZ2lvbiksIHN0YXQgPSAiaWRlbnRpdHkiKSArIGxhYnModGl0bGUgPSAiRmFjZWJvb2sgUGVuZXRyYXRpb24gUGVyY2VudCBieSBTdGF0ZSIsIHg9IlJlZ2lvbiIsIHk9IlBlcmNlbnQiKQ0KfSkNCg0KcmVuZGVyUGxvdCh7ZGY4ICU+JSBkcGx5cjo6c2VsZWN0KHJlZ2lvbiwgUGVyY2VudDE1dG8xOVBvcHVsYXRpb24pICU+JSBkcGx5cjo6ZmlsdGVyKHJlZ2lvbiAlaW4lIGMoIldhc2hpbmd0b24iLCAiQWxhc2thIiwgIk5ldyBKZXJzZXkiKSkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcmVnaW9uLCB5ID0gUGVyY2VudDE1dG8xOVBvcHVsYXRpb24sIGZpbGwgPSByZWdpb24pLCBzdGF0ID0gImlkZW50aXR5IikgKyBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgMTUtMTkgWWVhciBPbGRzIGJ5IFN0YXRlIiwgeD0iUmVnaW9uIiwgeT0iUGVyY2VudCIpDQp9KQ0KDQpyZW5kZXJQbG90KHtkZjggJT4lIGRwbHlyOjpzZWxlY3QocmVnaW9uLCBQZXJjZW50NDB0bzQ0UG9wdWxhdGlvbikgJT4lIGRwbHlyOjpmaWx0ZXIocmVnaW9uICVpbiUgYygiV2FzaGluZ3RvbiIsICJBbGFza2EiLCAiTmV3IEplcnNleSIpKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSByZWdpb24sIHkgPSBQZXJjZW50NDB0bzQ0UG9wdWxhdGlvbiwgZmlsbCA9IHJlZ2lvbiksIHN0YXQgPSAiaWRlbnRpdHkiKSArIGxhYnModGl0bGUgPSAiUGVyY2VudCBvZiA0MC00NCBZZWFyIE9sZHMgYnkgU3RhdGUiLCB4PSJSZWdpb24iLCB5PSJQZXJjZW50IikNCn0pDQoNCmBgYA0KDQoqKiAgICoqDQojIyAqKlRyZW5kcyBpbiBwZXJjZW50IGNoYW5nZXMgYmV0d2VlbiAyMDA3IGFuZCAyMDEyIGJ5IHN0YXRlIG9mIGhvdXNlaG9sZCBpbmNvbWUgYW5kIGhvbWUgaW50ZXJuZXQgdXNhZ2UgKHZlcnkgSW50ZXJlc3RpbmcpKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpJIHdhbnRlZCB0byBhbmFseXplIHRoZSBwYXR0ZXJucyBvZiBpbmNvbWUgYW5kIGludGVybmV0IHVzYWdlIGJldHdlZW4gMjAwNyBhbmQgMjAxMi4gVGhlcmVmb3JlLCBJIGpvaW5lZCAyMDEyIGFuZCAyMDA3IHRhYmxlcyBvZiBpbnRlcm5ldCB1c2FnZSBpbiBvbmUgcXVlcnkgYW5kIDIwMTIgYW5kIDIwMDcgdGFibGVzIG9mIGhvdXNlaG9sZCBpbmNvbWUgaW4gYSBzZWNvbmQgcXVlcnkuIFNpbmNlIHBvcHVsYXRpb25zIGNvdWxkIGNoYW5nZSwgSSBkZWNpZGVkIHRvIHVzZSBwZXJjZW50cyBiZWNhdXNlIGl0IHdhcyBhIG11Y2ggZWFzaWVyIG1lYXN1cmUgdG8gY29tcGFyZS4gSW4gdGhlIHF1ZXJ5IGl0c2VsZiwgSSBjcmVhdGVkIGEgY29sdW1uIHRoYXQgY2FsY3VsYXRlZCB0aGUgcGVyY2VudCBkaWZmZXJlbmNlIG9mIG51bWJlciBvZiBob21lIGludGVybmV0IHVzZXJzIGluIDIwMTIgdmVyc3VzIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIDIwMDcuIFRoZSBzZWNvbmQgcXVlcnkgY29udGFpbmVkIGEgY29sdW1uIHRoYXQgIGNhbGN1bGF0ZWQgdGhlIHBlcmNlbnQgY2hhbmdlIG9mIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBpbiAyMDEyIHZzIDIwMDcuDQoNCmBgYHtyfQ0KZGZfeiA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAwN0ludGVybmV0X2NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyAyMDA3SUFIb21lLA0KYDIwMTJpbnRlcm5ldF9jbGVhbmVkYC5udW1iZXJfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgQVMgMjAxMklBSG9tZSwNCmAyMDA3SW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLCAoYDIwMTJJbnRlcm5ldF9jbGVhbmVkYC5udW1iZXJfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUtYDIwMDdJbnRlcm5ldF9jbGVhbmVkYC5udW1iZXJfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUpL2AyMDA3SW50ZXJuZXRfY2xlYW5lZGAubnVtYmVyX29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lKjEwMCBhcyBob21lX3BlcmNlbnRfZGlmZmVyZW5jZQ0KRlJPTSBgMjAxMmludGVybmV0X2NsZWFuZWRgDQpKT0lOIDIwMDdJbnRlcm5ldF9jbGVhbmVkIE9OIGAyMDEySW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uICA9IGAyMDA3SW50ZXJuZXRfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KZGZfeSA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAwN0luY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUgQVMgMjAwN0FWSSwgYDIwMTJJbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lIEFTIDIwMTJBVkksIGAyMDEySW5jb21lX2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZSwNCihgMjAxMkluY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUtYDIwMDdJbmNvbWVfY2xlYW5lZGAuYXZlcmFnZV9ob3VzZWhvbGRfaW5jb21lKS9gMjAwN0luY29tZV9jbGVhbmVkYC5hdmVyYWdlX2hvdXNlaG9sZF9pbmNvbWUqMTAwIGFzIGluY29tZV9wZXJjZW50X2RpZmZlcmVuY2UNCkZST00gMjAxMkluY29tZV9jbGVhbmVkDQpKT0lOIDIwMDdJbmNvbWVfY2xlYW5lZCBPTiBgMjAxMkluY29tZV9jbGVhbmVkYC5yZWdpb24gID0gYDIwMDdJbmNvbWVfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpHYXRoZXJpbmcgaXMgbm90IG5lY2Vzc2FyeSBmb3IgdGhpcyBpbnNpZ2h0Lg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KV2hlbiBsb29raW5nIGF0IHRoZSBhdmVyYWdlIHBlcmNlbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIGNoYW5nZSBpbiBpbmNvbWUgYW5kIGNoYW5nZSBpbiBob21lIGludGVybmV0IHVzYWdlLCBvbmUgc3RhdGUgc3Rvb2Qgb3V0IGluIHBhcnRpY3VsYXIuIElkYWhvIGhhZCBhIDMuMTAlIGRlY3JlYXNlIGluIGF2ZXJhZ2UgaG91c2Vob2xkIGluY29tZSBmcm9tIDIwMDcgdG8gMjAxMi4gSG93ZXZlciwgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIHBlb3BsZSB3aG8gaGFkIGFjY2VzcyB0byBpbnRlcm5ldCBhdCBob21lIGluY3JlYXNlZCBieSAzNC4xOCUsIHRoZSBsYXJnZXN0IGluY3JlYXNlIG9mIGFueSBzdGF0ZS4gVGhpcyBzZWVtZWQgaGlnaGx5IHVudXN1YWw7IGhvd2V2ZXIgd2hlbiBkb2luZyBzb21lIHJlc2VhcmNoLCBpdCBzZWVtZWQgdGhhdCBJZGFobyBoYWQgYSBwcm9ncmFtIGJldHdlZW4gMjAwNCBhbmQgMjAwMTQgdGhhdCB3aWRlbmRlZCB0aGUgc2NvcGUgb2YgaW50ZXJuZXQgYnkgaW5jcmVhc2VpbmcgdGhlIG51bWJlciBvZiBob3VzZWhvbGRzIHdpdGggYnJvYWRiYW5kLiBUaGUgYXZlcmFnZSBob3VzZWhvbGQgaW5jb21lIHdlbnQgZG93biBiY2F1c2UgbW5heSBwcml2aXRlIHNlY3RvciBhbmQgdGVjaCBjb21wYW5pZXMgd2VyZSBoaXJlaW5nIGJpZyB0aW1lIGJ1dCBub3QgYSBsb3Qgb2YgdGhlbSB3ZXJlIGxvY2F0ZWQgaW4gSWRhaG8uDQoNCmBgYHtyfQ0KDQpyZW5kZXJQbG90KHtkZl96ICU+JSAgZHBseXI6OnNlbGVjdChTdGF0ZSxob21lX3BlcmNlbnRfZGlmZmVyZW5jZSklPiUgZ2dwbG90KCkgKyBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHg9U3RhdGUsIHk9IGhvbWVfcGVyY2VudF9kaWZmZXJlbmNlLCBmaWxsID0gImJsdWUiKSwgc3RhdD0iaWRlbnRpdHkiKSArIGxhYnModGl0bGUgPSAiSG9tZSBJbnRlcm5ldCBVc2FnZSBQZXJjZW50IERpZmZlcmVuY2UgYnkgU3RhdGUgMjAwNyAtIDIwMTIiLCB4PSJTdGF0ZSIsIHk9IlBlcmNlbnQgQ2hhbmdlIil9KQ0KDQpyZW5kZXJQbG90KHtkZl95ICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlLGluY29tZV9wZXJjZW50X2RpZmZlcmVuY2UpJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PSBpbmNvbWVfcGVyY2VudF9kaWZmZXJlbmNlLCBmaWxsID0gImdyZWVuIiksIHN0YXQ9ImlkZW50aXR5IikgKyBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZSBQZXJjZW50IERpZmZlcmVuY2UgYnkgU3RhdGUgMjAwNyAtIDIwMTIiLCB4PSJTdGF0ZSIsIHk9IlBlcmNlbnQgQ2hhbmdlIil9KQ0KDQoNCmBgYA0KDQoqKiAgICoqDQojIyAqKlJlbGF0aW9ucyBiZXR3ZWVuIGludGVybmV0IHVzYWdlIGF0IGhvbWUgdmVyc3VzIGludGVybmV0IHVzYWdlIG91dHNpZGUgb2YgdGhlIGhvbWUgZnJvbSAyMDA3IHRvIDIwMTIqKg0KDQoNCioqSW5wdXR0aW5nIHRoZSBDU1YgaW50byBSKioNCg0KSSB3YW50ZWQgdG8gc2VlIHRoZSByZWxhdGlvbiBiZXR3ZWVuIGhvbWUgaW50ZXJuZXQgdXNhZ2UgYW5kIG91dHNpZGUgdGhlIGhvdXNlIGludGVybmV0IHVzYWdlIGluIDIwMDcgYW5kIDIwMTIuIEkgY3JlYXRlZCB0d28gc2VwZXJhdGUgcXVlcnlzLCBvbmUgZm9yIDIwMDcgYW5kIG9uZSBmb3IgMjAxMiB0aGF0IHB1bGxlZCB0aGUgbnVtYmUgcm9mIGluZGl2aWR1YWxzIHdobyBhY2Nlc3NlZCBpbnRlcm5ldCBmcm9tIGhvbWUgYW5kIGZyb20gb3V0c2lkZSBvZiBob21lIGZvciBlYWNoIHN0YXRlLg0KDQpgYGB7cn0NCg0KZGZfdyA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAwN0ludGVybmV0X0NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyBJQV8yMDA3X0hvbWUsDQpgMjAwN0ludGVybmV0X0NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X291dHNpZGVfb2ZfaG91c2Vob2xkIEFTIElBXzIwMDdfT3V0c2lkZSwNCmAyMDA3SW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlIA0KRlJPTSAyMDA3SW50ZXJuZXRfQ2xlYW5lZCIpLCBkYXRhc2V0PXByb2plY3QpDQoNCg0KZGZfeCA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAxMkludGVybmV0X0NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyBJQV8yMDEyX0hvbWUsDQpgMjAxMkludGVybmV0X0NsZWFuZWRgLm51bWJlcl9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X291dHNpZGVfb2ZfaG91c2Vob2xkIEFTIElBXzIwMTJfT3V0c2lkZSwNCmAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlDQpGUk9NIDIwMTJJbnRlcm5ldF9DbGVhbmVkIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpHYXRoZXJpbmcgaXMgbm90IG5lY2Vzc2FyeSBmb3IgdGhpcyBpbnNpZ2h0Lg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KSW4gMjAwNywgdGhlcmUgd2VyZSBhY3R1YWxseSBtb3JlIHBlb3BsZSB1c2luZyB0aGUgaW50ZXJuZXQgZnJvbSBob21lLCB0aGFuIHRoZXJlIHdlcmUgcGVvcGxlIHVzaW5nIHRoZSBpbnRlcm5ldCBvdXRzaWRlIG9mIHRoZSBob3VzZWhvbGQuIEluIDIwMTIsIHRoZSBleGFjdCBvcHBvc2l0ZSBpcyBvYnNlcnZlZC4gVGhpcyBtYXkgYmUgZHVlIHRvIGFkdmFuY2VtZW50cyBpbiB0ZWNobm9sb2d5IGFuZCBpbnRlcm5ldCBlZmZpY2llbmN5IGFuZCBhIHdpZGVyIHNwcmVhZCBvZiBpbnRlcm5ldCBhY3Jvc3MgdGhlIGdsb2JlLiBNb3JlIGFuZCBtb3JlIHNtYWxsIGFuZCBsYXJnZSBidXNpbmVzc2VzIGJlZ2FuIGludm9sdmluZyBtb3JlIGludGVybmV0IGJhc2VkIHNlcnZpY2VzLiBGb3IgZXhhbXBsZSwgY29mZmVlIHNob3BzIGFyZSBub3cgYWxtb3N0IGV4cGVjdGVkIHRvIGhhdmUgYSBmcmVlIGludGVybmV0IHNlcnZpY2UsIGFuZCBtb3JlIHBlb3BsZSBhcmUgdXNpbmcgdGhpcyBhcyBhIHBsYWNlIHRvIGRvIHdvcmssIGluc3RlYWQgb2YgYXQgaG9tZS4gVGhpcyBtb3N0IGxpa2VseSBkcm92ZSB0aGUgbnVtYmVyIG9mIHBlb3BsZSB1c2luZyB0aGUgaW50ZXJuZXQgb3V0c2lkZSB0aGUgaG9tZS4gSXQgY2FuIGJlIHNlZW4gY2xlYXJseSB3aGVuIGNvbXBhcmluZyB0byB0aGUgdG90YWwgVVMgbnVtYmVyLg0KDQpgYGB7ciBlY2hvPVRSVUV9DQoNCnJlbmRlclBsb3Qoe2RmX3cgJT4lIGRwbHlyOjpzZWxlY3QoU3RhdGUsSUFfMjAwN19Ib21lLElBXzIwMDdfT3V0c2lkZSklPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT0gSUFfMjAwN19Ib21lKSkgKyBsYWJzKHRpdGxlID0gIkhvbWUgaW50ZXJuZXQgdXNhZ2UgaW4gMjAwNyIsIHg9IlN0YXRlIiwgeT0iTnVtYmVyIG9mIHVzZXJzIil9KQ0KDQpyZW5kZXJQbG90KHtkZl93ICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlLElBXzIwMDdfSG9tZSxJQV8yMDA3X091dHNpZGUpJT4lIGdncGxvdCgpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9U3RhdGUsIHk9IElBXzIwMDdfT3V0c2lkZSkpICsgbGFicyh0aXRsZSA9ICJPdXRzaWRlIGludGVybmV0IHVzYWdlIGluIDIwMDciLCB4PSJTdGF0ZSIsIHk9Ik51bWJlciBvZiB1c2VycyIpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfeCAlPiUgZHBseXI6OnNlbGVjdChTdGF0ZSxJQV8yMDEyX0hvbWUsSUFfMjAxMl9PdXRzaWRlKSU+JSBnZ3Bsb3QoKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PSBJQV8yMDEyX0hvbWUpKSArIGxhYnModGl0bGUgPSAiSG9tZSBpbnRlcm5ldCB1c2FnZSBpbiAyMDEyIiwgeD0iU3RhdGUiLCB5PSJOdW1iZXIgb2YgdXNlcnMiKX0pDQoNCnJlbmRlclBsb3Qoe2RmX3ggJT4lIGRwbHlyOjpzZWxlY3QoU3RhdGUsSUFfMjAxMl9Ib21lLElBXzIwMTJfT3V0c2lkZSklPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT0gSUFfMjAxMl9PdXRzaWRlKSkgKyBsYWJzKHRpdGxlID0gIk91dHNpZGUgaW50ZXJuZXQgdXNhZ2UgaW4gMjAxMiIsIHg9IlN0YXRlIiwgeT0iTnVtYmVyIG9mIHVzZXJzIil9KQ0KDQpgYGANCg0KKiogICAqKg0KIyMgKipGYWNlYm9vayB1c2VycyB2cyBtb2RlIG9mIEludGVybmV0IHVzYWdlIGluIDIwMDcqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkkgd2FudGVkIHRvIGNvbXBhcmUgdGhlIG51bWJlciBvZiBGYWNlYm9vayB1c2VycyBvZiBlYWNoIHN0YXRlIHRvIGVhY2ggc3RhdGUncyBtb2RlIG9mIGludGVybmV0IHVzYWdlLiBJIGNyZWF0ZWQgdHdvIHF1ZXJ5cywgb25lIHRoYXQgcHVsbGVkIHRoZSAyMDA3IHBlcmNlbnRzIGZvciBwZW9wbGUgd2hvIGhhZCBhY2Nlc3MgdG8gaW50ZXJuZXQgYXQgaG9tZSBhbmQgb3V0c2lkZSBvZiBob21lIGJ5IHN0YXRlIGFuZCBvbmUgdGhhdCBwdWxsZWQgdGhlIG51bWJlciBvZiBmYWNlYm9vayB1c2VycyBmb3IgZWFjaCBzdGF0ZS4NCg0KDQpgYGB7cn0NCg0KZGZfdSA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAwN0ludGVybmV0X0NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgQVMgSUFfMjAwN19Ib21lLA0KYDIwMDdJbnRlcm5ldF9DbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfb3V0c2lkZV9vZl9ob3VzZWhvbGQgQVMgSUFfMjAwN19PdXRzaWRlLA0KYDIwMDdJbnRlcm5ldF9DbGVhbmVkYC5yZWdpb24gYXMgU3RhdGUgDQpGUk9NIDIwMDdJbnRlcm5ldF9DbGVhbmVkIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KDQpkZl90IDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGZhY2Vib29rX2NsZWFuZWQuZmFjZW9va191c2VycyBhcyB1c2VycywgcmVnaW9uIGFzIFN0YXRlDQpmcm9tIGZhY2Vib29rX2NsZWFuZWQiKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQoNCg0KYGBgDQoNCioqUmVmb3JtYXR0aW5nIGluIFIqKg0KDQpHYXRoZXJpbmcgaXMgbm90IG5lY2Vzc2FyeSBmb3IgdGhpcyBpbnNpZ2h0Lg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KSSBjcmVhdGVkIGEgbGluZSBncmFwaCB0aGF0IHNob3dlZCB0aGUgc3ByZWFkIG9mIHRoZSBkYXRhIGJ5IHVzaW5nIHRoZSBkcGx5ciBtdXRhdGUgZnVuY3Rpb24gd2l0aCBjdW1tZWFuLiBUaGlzIHNob3dlZCBob3cgdmFyaWVkIG1hbnkgc3RhdGVzIHdlcmUgYW5kIGhvdyBlYWNoIGNoYW5nZWQgdGhlIG1lYW4gb2YgdGhlIGRhdGEgc2V0LiBUaGUgZmluYWwgdmFsdWUgd2FzIHRoZSBvdmVyYWxsIG1lYW4gYW5kIHRoYXQgd2FzIHVzZWQgdG8gY29tcGFyZSB0byB0aGUgcmVzdCBvZiB0aGUgY2hhcnRzLiBJIG5vdGljZWQgdGhhdCBDYWxpZm9ybmlhIHdpdGggdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbiBvZiBGYWNlYm9vayB1c2Vycywgd2FzIGFjdHVhbGx5IGJlbG93IGF2ZXJhZ2UgaW4gYm90aCBwZXJjZW50IG9mIHBlb3BsZSB3aG8gdXNlZCBpbnRlcm5ldCBhdCBob21lIGFuZCBvdXRzaWRlIG9mIGhvbWUuIFRoaXMgaXMgdmVyeSBpbnRyaWd1aW5nIGJlY2F1c2Ugb25lIHdvdWxkIHRoaW5rIHRoYXQgdGhlIHBsYWNlIHdpdGggdGhlIG1vc3QgRmFjZWJvb2sgdXNlcnMgd291bGQgYWxzbyBoYXZlIGEgaGlnaGVyIGxldmVsIG9mIHBlb3BsZSB1c2luZyBpbnRlcm5ldCBmcm9tIGhvbWUgb3IgZnJvbSBvdXRzaWRlIG9mIHRoZSBob21lOyBob3dldmVyLCB0aGF0IHRyZW5kIGlzIG5vdCBzZWVuLiBUaGlzIG1heSBiZSBkdWUgdG8gaW5jcmVhc2Ugb2YgdGVjaG5vbG9naWNhbCBhZHZhbmNlcyBpbiBvdGhlciBzdGF0ZXMgYW5kIENhbGlmb3JuaWEga2VlcGluZyBhbGwgb2YgaXRzIGFkdmFuY2UgaW4gdGhlIGJheSBhcmVhLiBVc2VycyBpbiBvdGhlciBzdGF0ZXMgYXJlIG1vcmUgbGlrZWx5IHRvIHVzZSBpbnRlcm5ldCBmcm9tIGhvbWUgdGhhbiB0aG9zZSBpbiBDYWxpZm9ybmlhIGJlY2F1c2Ugb2YgdGhlIGZhc3QtcGFjZWQgbGlmZSB0aGVyZS4NCg0KYGBge3J9DQoNCnJlbmRlclBsb3Qoe2RmX3QgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgIT0gJ1VuaXRlZCBTdGF0ZXMnKSU+JSBkcGx5cjo6bXV0YXRlKGF2Z191c2VycyA9IGN1bW1lYW4odXNlcnMpKSAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT1hdmdfdXNlcnMsIGdyb3VwID0gMSkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQoNCnJlbmRlclBsb3Qoe2RmX3QgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgIT0gJ1VuaXRlZCBTdGF0ZXMnKSU+JSBkcGx5cjo6bXV0YXRlKGF2Z191c2VycyA9IGN1bW1lYW4odXNlcnMpKSAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT11c2VycywgZmlsbCA9IGF2Z191c2VycykpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSl9KQ0KDQpyZW5kZXJQbG90KHtkZl91ICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlICE9ICdVbml0ZWQgU3RhdGVzJyklPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT1JQV8yMDA3X0hvbWUsIGZpbGwgPSBJQV8yMDA3X0hvbWUpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfdSAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSAhPSAnVW5pdGVkIFN0YXRlcycpJT4lIGdncGxvdChtYXBwaW5nID0gYWVzKHg9U3RhdGUsIHk9SUFfMjAwN19PdXRzaWRlLCBmaWxsID0gSUFfMjAwN19PdXRzaWRlICkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSl9KQ0KDQoNCmBgYA0KKiogICAqKg0KIyMgKipGYWNlYm9vayB1c2VycyB2cyBtb2RlIG9mIEludGVybmV0IHVzYWdlIGluIDIwMTIqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkkgd2FudGVkIHRvIGFuYXlzZSB0aGUgcHJldmlvdXMgaW5zaWdodCBmdXJ0aGVyIGJ5IGxvb2tpbmcgYXQgbW9yZSByZWNlbnQgZGF0YSwgc28gSSBtYWRlIGEgc2ltaWxhciBxdWVyeSBidXQgZm9yIDIwMTIgbnVtYmVycyBmb3IgcGVvcGxlIHdobyBoYWQgYWNjZXNzIHRvIGludGVybmF0IGF0IGhvbWUgdnMgb3V0IG9mIHRoZSBob21lLg0KDQoNCmBgYHtyfQ0KDQpkZl92IDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyBJQV8yMDEyX0hvbWUsDQpgMjAxMkludGVybmV0X0NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9vdXRzaWRlX29mX2hvdXNlaG9sZCBBUyBJQV8yMDEyX091dHNpZGUsDQpgMjAxMkludGVybmV0X0NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZQ0KRlJPTSAyMDEySW50ZXJuZXRfQ2xlYW5lZCIpLCBkYXRhc2V0PXByb2plY3QpDQoNCg0KDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNCkdhdGhlcmluZyBpcyBub3QgbmVjZXNzYXJ5IGZvciB0aGlzIGluc2lnaHQuDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpGdXJ0aGVyIGFuYWx5emluZyBmcm9tIGEgcHJldmlvdXMgaW5zaWdodCwgSSBkZWNpZGVkIHRvIGxvb2sgYXQgMjAxMiBhcyB3ZWxsIHRvIHNlZSBpZiB0aGVyZSB3YXMgYSByZWxhdGlvbnNoaXAgdGhlcmUuIFNpbmNlIHRoZSBGYWNlYm9rIGRhdGEgd2FzIHRoZSBzYW1lLCBJIHVzZWQgdGhlIHByZXZpb3VzIGdyYXBoIGFuZCBwcmV2aW91cyBhdmVyYWdlLiBJIGNyZWF0ZWQgdHdvIG1vcmUgZ3JhcGhzIHRoYXQgc2hvd3MgdGhlIHBlcmNlbnQgb2YgcGVvcGxlIHdobyB1c2UgaW50ZXJuZXQgb3V0c2lkZSBvZiB0aGUgaG9tZSBhbmQgcGVyY2VudCBvZiBwZW9wbGUgd2hvIHVzZSB0aGUgaW50ZXJuZXQgYXQgaG9tZS4gSXQgc2VlbXMgYXMgdGhvdWdoIHRoZSBDYWxpZm9ybmlhIGFuZCBOZXcgWW9yaywgc3RhdGVzIHdpdGggdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIEZhY2Vib29rIHVzZXJzLCBhY3R1YWxseSB3ZXJlIGJlbG93IGF2ZXJhZ2UsIGV2ZW4gbG93ZXIgdGhhbiAyMDA3LiBUaGlzIGlzIHZlcnkgc3VycHJpc2luZyBiZWNhdXNlIGl0IHdvdWxkIHNlZW0gdGhhdCBhcyB0aW1lIGdvZXMgb24sIG1vcmUgYW5kIG1vcmUgcGVvcGxlIHdvdWxkIGJlIGFibGUgdG8gdXNlIGludGVybmV0IHN0cmFpZ2h0IGZyb20gdGhlaXIgaG9tZS4gSG93ZXZlciwgc2luY2UgcGVvcGxlIG9mdGVuIHdvcmsgZnJvbSB0aGUgb2ZmaWNlLCBpdCBtYWtlcyBzZW5zZSB3aHkgdGhlIHBlcmNlbnQgZm9yIHVzYWdlIGF0IGhvbWUgaXMgc28gbG93LCBlc3BlY2lhbGx5IGluIHRoZSBjaXRpZXMgd2l0aCBhIGhpZ2hlciBpbmR1c3RyaWFsIHRlY2gtc2F2dnkgYmFzZS4NCg0KYGBge3J9DQoNCnJlbmRlclBsb3Qoe2RmX3YgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgIT0gJ1VuaXRlZCBTdGF0ZXMnKSU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PUlBXzIwMTJfSG9tZSwgZmlsbCA9IElBXzIwMTJfSG9tZSkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSl9KQ0KDQpyZW5kZXJQbG90KHtkZl92ICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlICE9ICdVbml0ZWQgU3RhdGVzJyklPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1TdGF0ZSwgeT1JQV8yMDEyX091dHNpZGUsIGZpbGwgPSBJQV8yMDEyX091dHNpZGUgKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQoNCg0KYGBgDQoqKiAgICoqDQojIyAqKkludGVybmV0IEFjY2VzcyBWcyBBdmVyYWdlIEluY29tZSBSZXNwZWN0aXZlIHRvIDIwMDcgYW5kIDIwMTIqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkluIHRoaXMgc3RlcCwgSSB1c2VkIHRoZSBkYXRhLndvcmxkIG5vbi1zZWxlY3QgKiBTUUwgdG8gY3JlYXRlIHR3byB0aWJibGVzIGNvbnRhaW5pbmcgY29sdW1ucyBmcm9tIGZvdXIgZGlmZmVyZW50IGRhdGEgc291cmNlczogMjAwNyBpbnRlcm5ldCBhY2Nlc3MsIDIwMTIgaW50ZXJuZXQgYWNjZXNzLCAyMDA3IGluY29tZSwgYW5kIDIwMTIgaW5jb21lLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KYGBge3J9DQpkZl9hIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDA3SW50ZXJuZXRfQ2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyAyMDA3SUFIb21lLCANCmAyMDA3SW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLCANCmAyMDA3aW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyBBVkdfSW5jb21lMjAwNw0KRlJPTSAyMDA3SW50ZXJuZXRfQ2xlYW5lZCANCkpPSU4gYDIwMDdpbmNvbWVfY2xlYW5lZGAgT04gYDIwMDdJbnRlcm5ldF9DbGVhbmVkYC5yZWdpb24gID0gYDIwMDdpbmNvbWVfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KDQpkZl9iIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBBUyAyMDEySUFIb21lLCANCmAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLCANCmAyMDEyaW5jb21lX2NsZWFuZWRgLmF2ZXJhZ2VfaG91c2Vob2xkX2luY29tZSBhcyBBVkdfSW5jb21lMjAxMg0KRlJPTSAyMDEySW50ZXJuZXRfQ2xlYW5lZCANCkpPSU4gYDIwMTJpbmNvbWVfY2xlYW5lZGAgT04gYDIwMTJJbnRlcm5ldF9DbGVhbmVkYC5yZWdpb24gID0gYDIwMTJpbmNvbWVfY2xlYW5lZGAucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNClRoZSB0d28gc2NhdHRlcnBsb3RzIGNvbXBhcmVzIGludGVybmV0IGFjY2VzcyB0byBhdmVyYWdlIGluY29tZSB3aXRoIHJlc3BlY3QgdG8gU3RhdGUgYXMgd2VsbCBmb3IgYm90aCB5ZWFycyAyMDA3IGFuZCAyMDEyLiBBdCBmaXJzdCBnbGFuY2UsIHdlIHNlZSB0aGF0IHRoZXJlIGlzIGEgc3Ryb25nLCBwb3NpdGl2ZSwgbGluZWFyIGNvcnJlbGF0aW9uIGJldHdlZW4gaW50ZXJuZXQgYWNjZXNzIGFuZCBhdmVyYWdlIGluY29tZS4gIEFzIHNlZW4gaW4gdGhlIGRhdGEgYmVsb3csIHRoZSBTdGF0ZXMgd2l0aCAiaGlnaCIgbmF0aW9uYWwgYXZlcmFnZSBpbmNvbWUgaGF2ZSB0aGUgaGlnaGVzdCBwZXJjZW50YWdlIG9mIGludGVybmV0IGFjY2VzcyBhbmQgdGhlIFN0YXRlcyB3aXRoICJsb3ciIG5hdGlvbmFsIGF2ZXJhZ2UgaW5jb21lIGhhdmUgdGhlIGxvd2VzdCBwZXJjZW50YWdlIG9mIGludGVybmV0IGFjY2Vzcy4gVGhpcyBpcyBleHBlY3RlZCBhcyBTdGF0ZXMgd2l0aCB3ZWF0aGllciBpbmhhYml0YW50cyBjYW4gbW9yZSBsaWtlbHkgYWZmb3JkIGludGVybmV0IHNlcnZpY2VzLCB0aHVzIHRoZSBoaWdoZXIgaW50ZXJuZXQgcGVuZXRyYXRpb24gYW5kIHZpc2UgdmVyc2EuIEhvd2V2ZXIsIGl0IGlzIGludGVyZXN0aW5nIHRvIHNlZSB0aGF0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVybmV0IGFjY2VzcyBhbmQgYXZlcmFnZSBpbmNvbWUgaXMgc2lnbmlmaWNhbnRseSB3ZWFrZXIgaW4gdGhlIHllYXIgb2YgMjAxMiBhbmQgbW9yZSBzY2F0dGVyZWQuIEZ1cnRoZXJtb3JlLCB0aGUgc2xvcGUgb2YgYXZlcmFnZSBpbmNvbWUgdmVyc3VzIGludGVybmV0IGFjY2VzcyBpcyBhIGxvdCBsZXNzIHN0ZWVwIGluZGljYXRpbmcgU3RhdGVzIHdpdGggbG93ZXIgYXZlcmFnZSBpbmNvbWUgaW5jcmVhc2luZ2x5IGhpZ2ggcGVyY2VudGFnZXMgb2YgaW50ZXJuZXQgYWNjZXNzIHJlbGF0aXZlIHRvIHRoZSAyMDA3IGRpc3RyaWJ1dGlvbi4gVGh1cyBvbmUgY2FuIGNvbmNsdWRlIHRoYXQgd2l0aGluIHRoZSA1IHllYXIgdGltZSBmcmFtZSwgdGhlIGFmZm9yZGFiaWxpdHkgb2YgaW50ZXJuZXQgYWNjZXNzIGlzIG9uIHRoZSByaXNlLiBUaGlzIGNhbiBiZSBwcm9qZWN0ZWQgbG9uZyB0ZXJtIGFzIHdoZW4gYXMgdGVjaG5vbG9neSBhZHZhbmNlbWVudHMgaW5jcmVhc2Ugb3ZlcnRpbWUsIGNhdXNlIHRoZSBwcmljZSBvZiBwYXN0IHRlY2hub2xvZ2llcyB0byBkZWNyZWFzZS4gDQoNCg0KYGBge3J9DQpyZW5kZXJQbG90KHtkZl9hICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PWAyMDA3SUFIb21lYCwgeT1gQVZHX0luY29tZTIwMDdgLCBjb2xvcj1TdGF0ZSkpICsgZ2VvbV9wb2ludCgpKyBsYWJzKHRpdGxlID0gIjIwMDcgSW50ZXJuZXQgQWNlc3MgdnMgQXZlcmFnZSBJbmNvbWUiLCB4PSJJbnRlcm5ldCBBY2Nlc3MiLCB5PSJBdmVyYWdlIEluY29tZSIpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfYiAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1gMjAxMklBSG9tZWAsIHk9YEFWR19JbmNvbWUyMDEyYCwgY29sb3I9U3RhdGUpKSArIGdlb21fcG9pbnQoKSsgbGFicyh0aXRsZSA9ICIyMDEyIEludGVybmV0IEFjY2VzcyB2cyBBdmVyYWdlIEluY29tZSIsIHg9IkludGVybmV0IEFjY2VzcyIsIHk9IkF2ZXJhZ2UgSW5jb21lIil9KQ0KYGBgDQoNClRvIGZ1cnRoZXIgYW5hbHl6ZSBTdGF0ZSBhdmVyYWdlIGluY29tZSdzIGRpcmVjdCBlZmZlY3Qgb24gaW50ZXJuZXQgYW5kIEZhY2Vib29rIHBlbmV0cmF0aW9uIEkgY3JlYXRlIHR3byBwYXJhbWV0ZXJzLCBMb3cgSW5jb21lIGFuZCBIaWdoIEluY29tZSBiYXNlZCBvbiB0aGUgYWJvdmUgdmlzdWFsaXphdGlvbi4gV2l0aCB0aGVzZSBwYXJhbWV0ZXJzLCBJIHV0aWxpemUgdGhlIENhbGN1bGF0ZWQgRmllbGQgdG8gY3JlYXRlIGEgY3VzdG9tIGRpbWVuc2lvbiwgIkxldmVsIG9mIE5hdGlvbmFsIEF2ZXJhZ2UgSW5jb21lLiIgVXRpbGl6aW5nIHRoaXMgZGltZW5zaW9uIGluIHRhbmRlbSB3aXRoIFJlZ2lvbnMsIEkgY3JlYXRlZCBhIGNyb3NzdGFicyB0byBjb21wYXJlIGluY29tZSB3aXRoIEludGVybmV0IHBlbmV0cmF0aW9uLiBBcyBzZWVuIGluIHRoZSBkYXRhIGJlbG93LCB0aGUgU3RhdGVzIHdpdGggImhpZ2giIG5hdGlvbmFsIGF2ZXJhZ2UgaW5jb21lIGhhdmUgdGhlIGhpZ2hlc3QgaW50ZXJuZXQgcGVuZXRyYXRpb24gYW5kIHRoZSBTdGF0ZXMgd2l0aCAibG93IiBuYXRpb25hbCBhdmVyYWdlIGluY29tZSBoYXZlIHRoZSBsb3dlc3QgaW50ZXJuZXQgcGVuZXRyYXRpb24uIFRodXMgb25lIGNhbiBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIGEgc3Ryb25nLCBsaW5lYXIsIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gaW5jb21lIGFuZCBpbnRlcm5ldCBwZW5ldHJhdGlvbi4gVGhpcyBpcyBleHBlY3RlZCBhcyBTdGF0ZXMgd2l0aCB3ZWF0aGllciBpbmhhYml0YW50cyBjYW4gYWZmb3JkIHRvIGludGVybmV0IHNlcnZpY2VzLCB0aHVzIHRoZSBoaWdoZXIgaW50ZXJuZXQgcGVuZXRyYXRpb24gYW5kIHZpc2UgdmVyc2EuDQoNClNpbWlsYXJseSwgd2UgYW5hbHl6ZSB0aGUgZWFjaCBTdGF0ZSdzIGF2ZXJhZ2UgaW5jb21lJ3MgZWZmZWN0IG9uIEZhY2Vib29rIHBlbmV0cmF0aW9uIHVzaW5nIHRoZSBzYW1lIHBhcmFtZXRlcnMgYW5kIGNhbGN1bGF0ZWQgZmllbGRzIGFmb3JlbWVudGlvbmVkLiBXZSBzZWUgdGhlIHBhdHRlcm4gaXMgdGhlIHNhbWUuIFN0YXRlcyB3aXRoICJsb3ciIG5hdGlvbmFsIGF2ZXJhZ2UgaW5jb21lIGhhdmUgdGhlIGxvd2VzdCBGYWNlYm9vayBwZW5ldHJhdGlvbiwgd2hlcmVhcyBTdGF0ZXMgd2l0aCAiaGlnaCIgbmF0aW9uYWwgYXZlcmFnZSBpbmNvbWUgaGF2ZSB0aGUgaGlnaCBGYWNlYm9vayBwZW5ldHJhdGlvbi4gVGhpcyBleGVtcGxpZmllcyBhIHN0cm9uZywgbGluZWFyLCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGluY29tZSBhbmQgRmFjZWJvb2sgcGVuZXRyYXRpb24gYXMgd2VsbC4gVGhpcyB2YWxpZGF0ZXMgdGhlIGNvbmNsdXNpb24gZHJhd24gYWJvdmUgYXMgcG9vcmVyIGluaGFiaXRhbnRzIGFyZSBsZXNzIGxpa2VseSB0byBiZSBhYmxlIHRvIGFmZm9yZCBpbnRlcm5ldCBzZXJ2aWNlcywgbG93ZXJpbmcgdGhlIGludGVybmV0IHBlbmV0cmF0aW9uIGFuZCBpbiByZXR1cm4gbG93ZXJpbmcgRmFjZWJvb2sgcGVuZXRyYXRpb24gYmVjYXVzZSBvbmUgY2Fubm90IGFjY2VzcyBGYWNlYm9vayB3aXRob3V0IGludGVybmV0IGFjY2Vzcy4NCg0KKiogICAqKg0KIyMgKipJbnRlcm5ldCBQZW5ldHJhdGlvbiBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbiBWcyBJbnRlcm5ldCBBY2Nlc3MqKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkluIHRoaXMgc3RlcCwgSSB1c2VkIHRoZSBkYXRhLndvcmxkIG5vbi1zZWxlY3QgKiBTUUwgdG8gY3JlYXRlIHR3byB0aWJibGVzIGNvbnRhaW5pbmcgY29sdW1ucyBmcm9tIHRocmVlIGRpZmZlcmVudCBkYXRhIHNvdXJjZXM6IGludGVybmV0IHBlbmV0cmF0aW9uLCBGYWNlYm9vayBwZW5ldHJhdGlvbiwgYW5kIGludGVybmV0IGFjY2VzcyBwZXJjZW50YWdlLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KYGBge3J9DQpkZl9hYSA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAxMkludGVybmV0X0NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9mcm9tX2hvbWUgQVMgSW50ZXJuZXRBY2Nlc3MyLCANCmAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLA0KZmFjZWJvb2tfY2xlYW5lZC5mYWNlYm9va19wZW5ldHJhdGlvbiBhcyBGQl9QZW4yDQpGUk9NIDIwMTJJbnRlcm5ldF9DbGVhbmVkIA0KSk9JTiBmYWNlYm9va19jbGVhbmVkIE9OIGAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uID0gZmFjZWJvb2tfY2xlYW5lZC5yZWdpb24iKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQpkZl9jIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGZhY2Vib29rX2NsZWFuZWQuaW50ZXJuZXRfcGVuZXRyYXRpb24gYXMgTkVUX1BlbiwgDQpmYWNlYm9va19jbGVhbmVkLmZhY2Vib29rX3BlbmV0cmF0aW9uIGFzIEZCX3BlbiwNCmZhY2Vib29rX2NsZWFuZWQucmVnaW9uIGFzIFN0YXRlDQpGUk9NIEZhY2Vib29rX0NsZWFuZWQiKSwgZGF0YXNldD1wcm9qZWN0KQ0KDQpkZl9kIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDEyaW50ZXJuZXRfY2xlYW5lZGAucGVyY2VudF9vZl9pbmRpdmlkdWFsc193aG9fYWNjZXNzX2ludGVybmV0X2Zyb21faG9tZSBhcyBJQWhvbWUsDQpgMjAxMmludGVybmV0X2NsZWFuZWRgLnBlcmNlbnRfb2ZfaW5kaXZpZHVhbHNfd2hvX2FjY2Vzc19pbnRlcm5ldF9vdXRzaWRlX29mX2hvdXNlaG9sZCBhcyBJQW91dHNpZGUsDQpgMjAxMmludGVybmV0X2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZQ0KRlJPTSAyMDEyaW50ZXJuZXRfY2xlYW5lZCIpLCBkYXRhc2V0PXByb2plY3QpDQoNCmRmX2UgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KKCJTRUxFQ1QgYDIwMTJJbnRlcm5ldF9DbGVhbmVkYC5wZXJjZW50X29mX2luZGl2aWR1YWxzX3dob19hY2Nlc3NfaW50ZXJuZXRfZnJvbV9ob21lIEFTIEludGVybmV0QWNjZXNzLCANCmAyMDEySW50ZXJuZXRfQ2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlLA0KZmFjZWJvb2tfY2xlYW5lZC5pbnRlcm5ldF9wZW5ldHJhdGlvbiBhcyBORVRfUGVuMg0KRlJPTSAyMDEySW50ZXJuZXRfQ2xlYW5lZCANCkpPSU4gZmFjZWJvb2tfY2xlYW5lZCBPTiBgMjAxMkludGVybmV0X0NsZWFuZWRgLnJlZ2lvbiA9IGZhY2Vib29rX2NsZWFuZWQucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCmBgYA0KDQoqKlJlZm9ybWF0dGluZyBpbiBSKioNCg0KVGhlIG5leHQgc3RlcCBpbiB0aGUgZGF0YSBzY2llbmNlIHBpcGVsaW5lIGlzIHRvIGdhdGhlciB0aGUgY29sdW1ucyBpbnRvIGEgc2V0IG9mIGtleSB2YWx1ZSBwYWlycy4gSG93ZXZlciwgZm9yIHRoaXMgY3VycmVudCBpbnNpZ2h0LCBnYXRoZXJpbmcgd2FzIG5vdCBuZWVkZWQuDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KDQpGaXJzdCBJIGNvbXBhcmUgdGhlIHBlcmNlbnQgdGlsZXMgb2YgaW5kaXZpZHVhbHMgd2hvIGhhcyBhY2Nlc3MgdG8gaW50ZXJuZXQgb2YgaW5zaWRlIG9mIGhvdXNlaG9sZCB0byB0aGUgcGVyY2VudGFnZSBvZiBpbmRpdmlkdWFscyB3aG8gaGF2ZSBhY2Nlc3MgdG8gaW50ZXJuZXQgb3V0c2lkZSBvZiBob3VzZWhvbGQuIEFzIGV4cGVjdGVkLCBJIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBhIGV4dHJlbWVseSBzdHJvbmcsIHBvc2l0aXZlLCBsaW5lYXIgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4gT25lIGNhbiBhc3N1bWUgdGhhdCBwZW9wbGUgd2l0aCBhY2Nlc3MgdG8gaW50ZXJuZXQgZnJvbSBob21lIHNob3VsZCBoYXZlIGFjY2VzcyB0byBpbnRlcm5ldCBvdXRzaWRlIG9mIGhvbWUgYXMgd2VsbC4gRnVydGhlcm1vcmUsIG9uZSBjYW4gYXNzdW1lIHRoZXNlIHR3byB2YXJpYWJsZXMgY2FuIGJlIHVzZWQgaW50ZXJjaGFuZ2VhYmx5IG5vdy4gDQoNCmBgYHtyfQ0KcmVuZGVyUGxvdCh7ZGZfZCAlPiUNCiAgZ2dwbG90KCkgKyANCiAgICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHg9YElBaG9tZWAsIGZpbGwgPSBTdGF0ZSksIGJpbnMgPSAxMCkgKyANCiAgICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgdGhlIFBvcHVsYWNlIHdpdGggSW50ZXJuZXQgQWNjZXNzIEZyb20gSG9tZSBSZXNwZWN0aXZlIHRvIFN0YXRlIiwgeD0iUGVyY2VudCBvZiBJbnRlcm5ldCBBY2Nlc3MgRnJvbSBIb21lIiwgeT0iQ291bnQiKX0pDQoNCnJlbmRlclBsb3Qoe2RmX2QgJT4lDQogIGdncGxvdCgpICsgDQogICAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4PWBJQW91dHNpZGVgLCBmaWxsID0gU3RhdGUpLCBiaW5zID0gMTApICsgDQogICAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIHRoZSBQb3B1bGFjZSB3aXRoIEludGVybmV0IEFjY2VzcyBGcm9tIE91dHNpZGUgb2YgSG9tZSBSZXNwZWN0aXZlIHRvIFN0YXRlIiwgeD0iUGVyY2VudCBvZiBJbnRlcm5ldCBBY2Nlc3MgRnJvbSBIb21lIiwgeT0iQ291bnQiKX0pDQpgYGANCg0KDQpGYWNlYm9vayBwZW5ldHJhdGlvbiBpcyB0aGUgcmF0aW8gb2YgRmFjZWJvb2sgdXNlcnMgdG8gcG9wdWxhdGlvbiBhbmQgaW50ZXJuZXQgcGVuZXRyYXRpb24gaXMgbWVhc3VyZXMgaW50ZXJuZXQgdXNlcnMgdG8gcG9wdWxhdGlvbi5Mb29raW5nIGF0IHRoZSBJbnRlcm5ldCB2ZXJzdXMgRmFjZWJvb2sgUGVuZXRyYXRpb24gcGxvdCwgb25lIGNhbiBzZWUgdGhhdCB0aGUgRGlzdHJpY3Qgb2YgQ29sdW1iaWEgaXMgYW4gZXh0cmVtZSBvdXRsaWVyIGZvciBGYWNlYm9vayBwZW5ldHJhdGlvbi4gSG93ZXZlciwgd2hlbiBpdCBjb21lcyB0byBJbnRlcm5ldCBwZW5ldHJhdGlvbiwgRC5DLiBoYXMgYSBub3JtYWxpemVkIHZhbHVlLiBVcG9uIGZ1cnRoZXIgYW5hbHlzaXMsIHRoZXJlIGFwcGVhcnMgdG8gYmUgYSBwb3NpdGl2ZSwgbGluZWFyIGNvcnJlbGF0aW9uIGJldHdlZW4gSW50ZXJuZXQgcGVuZXRyYXRpb24gYW5kIEZhY2Vib29rIHBlbmV0cmF0aW9uLiBUaGlzIGlzIGV4cGVjdGVkLCBhcyBvbmUgc2hvdWxkIGV4cGVjdCB0aGF0IGFyZWFzIHdpdGggaGlnaGVyIGludGVybmV0IHBlbmV0cmF0aW9uIHNob3VsZCBoYXZlIGEgaGlnaGVyIEZhY2Vib29rIHBlbmV0cmF0aW9uLiBIb3dldmVyLCBpbnRlcmVzdGluZyBlbm91Z2ggIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gaXMgbm90IHN0cm9uZyBhdCBhbGwsIHBlcmhhcHMgZmV3ZXIgcGVvcGxlIHVzZSBGYWNlYm9vayB0aGFuIG9uZSB3b3VsZCB0eXBpY2FsbHkgaW1hZ2luZS4gQW5hbHl6aW5nIHRoZSBJbnRlcm5ldCBQZW5ldHJhdGlvbiB2ZXJzdXMgd2Ugc2VlIHRoYXQgdGhlcmUgaXMgaW4gZmFjdCBhIGRpcmVjdCBwb3NpdGl2ZSBjb3JyZXNwb25kZW5jZSBiZXR3ZWVuIHBlcmNlbnRhZ2Ugb2YgaW50ZXJuZXQgYWNjZXNzIGFuZCBpbnRlcm5ldCBwZW5ldHJhdGlvbi4gVGhpcyBpcyBleHBlY3RlZCBhcyBhcmVhcyB3aXRoIGhpZ2ggaW50ZXJuZXQgYWNjZXNzIHBlcmNlbnRhZ2VzLCBzaG91bGQgaGF2ZSBoaWdoZXIgaW50ZXJuZXQgcGVuZXRyYXRpb24gYXMgcG9wdWxhdGlvbiBpcyBhIGZhY3RvciBpbiBib3RoLiBTZWVuIHRoYXQgdGhlcmUgaXMgaW50ZXJuZXQgcGVuZXRyYXRpb24gYW5kIGludGVybmV0IGFjY2VzcyBwZXJjZW50YWdlcyBhcmUgaG9tb2dlbmVvdXMgaW4gbmF0dXJlLCB3ZSBjYW4gY29uY2x1ZGUgdGhhdCBhZm9yZW1lbnRpb25lZCBhbmFseXNpcyBvbiBpbnRlcm5ldCBhY2Nlc3MgY2FuIGJlIGRpcmVjdGx5IGFwcGxpZWQgdG8gaW50ZXJuZXQgcGVuZXRyYXRpb24gYXMgd2VsbCBhbmQgdmlzZSB2ZXJzYS4NCg0KYGBge3J9DQpyZW5kZXJQbG90KHtkZl9jICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PWBORVRfUGVuYCwgeT1gRkJfcGVuYCwgY29sb3I9U3RhdGUpKSArIGdlb21fcG9pbnQoKSsgbGFicyh0aXRsZSA9ICJJbnRlcm5ldCBQZW5ldHJhdGlvbiB2cyBGYWNlYm9vayBQZW5ldHJhdGlvbiIsIHg9IkludGVybmV0IFBlbmV0cmF0aW9uIiwgeT0iRmFjZWJvb2sgUGVuZXRyYXRpb24iKX0pDQoNCnJlbmRlclBsb3Qoe2RmX2FhICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PWBJbnRlcm5ldEFjY2VzczJgLCB5PWBGQl9QZW4yYCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyBsYWJzKHRpdGxlID0gIkludGVybmV0IFBlbmV0cmF0aW9uIHZzIEludGVybmV0IEFjY2VzcyIsIHg9IkludGVybmV0IEFjY2VzcyIsIHk9IkludGVybmV0IFBlbmV0cmF0aW9uIil9KQ0KDQpyZW5kZXJQbG90KHtkZl9lICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PWBJbnRlcm5ldEFjY2Vzc2AsIHk9YE5FVF9QZW4yYCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArIGxhYnModGl0bGUgPSAiSW50ZXJuZXQgUGVuZXRyYXRpb24gdnMgSW50ZXJuZXQgQWNjZXNzIiwgeD0iSW50ZXJuZXQgQWNjZXNzIiwgeT0iSW50ZXJuZXQgUGVuZXRyYXRpb24iKX0pDQpgYGANCg0KKiogICAqKg0KIyMgKipHZW5kZXIgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24qKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkluIHRoaXMgc3RlcCwgSSB1c2VkIHRoZSBkYXRhLndvcmxkIG5vbi1zZWxlY3QgKiBTUUwgdG8gY3JlYXRlIHR3byB0aWJibGVzIGNvbnRhaW5pbmcgY29sdW1ucyBmcm9tIHR3byBkaWZmZXJlbnQgZGF0YSBzb3VyY2VzOiBwb3B1bGF0aW9uIChtYWxlLCBmZW1hbGUgYW5kIHRvdGFsKSBhbmQgRmFjZWJvb2sgcGVuZXRyYXRpb24uIFRoZSBjb2RlIGZvciB0aGlzIGlzIHNob3duIGluIHRoZSBzY3JlZW5zaG90IGJlbG93Lg0KDQpgYGB7cn0NCmRmX2YgPC0gZGF0YS53b3JsZDo6cXVlcnkoZGF0YS53b3JsZDo6cXJ5X3NxbA0KKCJTRUxFQ1QgYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLmZlbWFsZV90b3RhbF9wb3B1bGF0aW9uIGFzIGZlbWFsZV9wb3AsDQpgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfcG9wdWxhdGlvbiBhcyB0b3RhbF9wb3AsDQpmYWNlYm9va19jbGVhbmVkLmZhY2Vib29rX3BlbmV0cmF0aW9uIGFzIEZCX1BlbjIsDQpgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlDQpGUk9NIDIwMTJwb3B1bGF0aW9uX2NsZWFuZWQgDQpKT0lOIGZhY2Vib29rX2NsZWFuZWQgT04gYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiA9IGZhY2Vib29rX2NsZWFuZWQucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCg0KZGZfZyA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAubWFsZV90b3RhbF9wb3B1bGF0aW9uIGFzIG1hbGVfcG9wLA0KYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnRvdGFsX3BvcHVsYXRpb24gYXMgdG90YWxfcG9wLA0KZmFjZWJvb2tfY2xlYW5lZC5mYWNlYm9va19wZW5ldHJhdGlvbiBhcyBGQl9QZW4yLA0KYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZQ0KRlJPTSAyMDEycG9wdWxhdGlvbl9jbGVhbmVkIA0KSk9JTiBmYWNlYm9va19jbGVhbmVkIE9OIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC5yZWdpb24gPSBmYWNlYm9va19jbGVhbmVkLnJlZ2lvbiIpLCBkYXRhc2V0PXByb2plY3QpDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KSW50ZXJlc3RpbmcgZW5vdWdoLCByZWdhcmRpbmcgRmFjZWJvb2sgUGVuZXRyYXRpb24sIHdlIHNlZSB0aGF0IHRoZSBEZWxhd2FyZSByYW5rZWQgdGhlIGxvd2VzdC4gSWYgd2VhbHRoIGFuZCBwb3B1bGF0aW9uIHNpemUgYXJlIGNvbnRyaWJ1dGluZyBmYWN0b3JzIHRvIEZhY2Vib29rIFBlbmV0cmF0aW9uLCBpdCBpcyBvZGQgdG8gc2VlIERlbGF3YXJlIHJhbmtlZCB0aGUgbG93ZXN0LiBPbmx5IDEyJSBvZiBEZWxhd2FyZSdzIHBvcHVsYXRpb24gaXMgYmVsb3cgdGhlIHBvdmVydHkgbGV2ZWwsIHdoZXJlYXMgMTYlIG9mIHRoZSBuYXRpb25hbCBwb3B1bGF0aW9uIGlzIGJlbG93IHRoZSBwb3ZlcnR5IGxldmVsLiBUaGUgcG9wdWxhdGlvbiBzaXplIG9mIERlbGF3YXJlIGlzIDkwMCwwMDAgcG9ydHJheWluZyB0aGF0IERlbGF3YXJlIGlzIGJvdGggZWNvbm9taWNhbGx5IHdlbGwgb2ZmIGFuZCBzbWFsbGVyIGluIHBvcHVsYXRpb24gY29tcGFyZWQgdG8gb3RoZXIgU3RhdGVzLiBIb3dldmVyLCBvbmUgd291bGQgZXhwZWN0IHN1Y2ggYSBTdGF0ZSB0byBoYXZlIGhpZ2hlciBGYWNlYm9vayBwZW5ldHJhdGlvbi4NCg0KR2l2ZW4gdGhhdCB0aGUgRGlzdHJpY3Qgb2YgQ29sdW1iaWEgaXMgYW4gZXh0cmVtZSBvdXRsaWVyLCBJIGV4dHJhcG9sYXRlIGl0LiBUaGVuIEkgdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24sIGdlbmRlciBieSBjcmVhdGluZyBjYWxjdWxhdGVkIGZpZWxkcywgd2hpY2ggSSBpbXBsZW1lbnQgYnkgdXRpbGl6aW5nIG11dGF0ZSBhcyBzZWVuIGJlbG93LCB0byBkZW5vdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZ2VuZGVyIHR5cGUgcmVzcGVjdGl2ZSB0byBlYWNoIFN0YXRlLiBGaXJzdCBJIGNyZWF0ZSB0d28gbGluZSBwbG90cywgdG8gdmlzdWFsaXplIHRoZSBnZW5kZXIgZGlzY3JlcGVuY3kgcmVsYXRpdmUgdG8gZWFjaCBTdGF0ZS4gQXMgc2VlbiBiZWxvdywgdGhlIHZhcmlhbmNlIGlzIHNpZ25pZmljYW50IGVub3VnaCB0byBwcm9jZWVkIHdpdGggYW5hbHlzaXMuIEFuYWx5emluZyBmdXJ0aGVyIGJ5IGltcGxlbWVudGluZyBiYXJncmFwaHMgdGhhdCBpbmNvcnBvcmF0ZSBnZW5kZXIgYXMgYSBmaWxsLiBUaGlzIGFsbG93cyB1cyB0byBkaWZmZXJlbnRpYXRlIEZhY2Vib29rIHBlbmV0cmF0aW9uIHJlbGF0aXZlIHRvIGdlbmRlciB0eXBlLiBMb29raW5nIGF0IHRoZSBkaXN0cmlidXRpb24sIEkgc2VlIHRoYXQgdGhlIHRvcCA1IFN0YXRlcyByYW5rZWQgaGlnaGVzdCBpbiBGYWNlYm9vayBwZW5ldHJhdGlvbiBhcmUgRC5DLiwgR2VvcmdpYSwgSWxsaW5vaXMsIFJob2RlIElzbGFuZCBhbmQgV2FzaGluZ3Rvbi4gSW50ZXJlc3RpbmcgZW5vdWdoLCBhbGwgZml2ZSBvZiB0aG9zZSBTdGF0ZXMgaGF2ZSBhIGdyZWF0ZXIgZmVtYWxlIHBvcHVsYXRpb24gYXMgc2VlbiBpbiB0aGUgcGxvdHMgYmVsb3cuIE9uZSBtYXkgY29uY2x1ZGUgdGhhdCBnZW5kZXIgaGFzIGEgZGlyZWN0IGVmZmVjdCBvbiBGYWNlYm9vayBwZW5ldHJhdGlvbi4NCg0KYGBge3J9DQpyZW5kZXJQbG90KHtkZl9mICU+JSBkcGx5cjo6ZmlsdGVyKFN0YXRlICE9ICdEaXN0cmljdCBvZiBDb2x1bWJpYScpJT4lIGRwbHlyOjptdXRhdGUocGVyY2VudEZlbWFsZSA9ICgoYGZlbWFsZV9wb3BgKS8oYHRvdGFsX3BvcGApKSoxMDApICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PXBlcmNlbnRGZW1hbGUsIGdyb3VwID0gMSkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKCkgKyBsYWJzKHRpdGxlID0gIkZlbWFsZSBQb3B1bGF0aW9uIFBlcmNlbnRhZ2UgRGlzdHJpYnV0aW9uIikrIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfZiAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSAhPSAnRGlzdHJpY3Qgb2YgQ29sdW1iaWEnKSU+JSBkcGx5cjo6bXV0YXRlKHBlcmNlbnRGZW1hbGUgPSAoKGBmZW1hbGVfcG9wYCkvKGB0b3RhbF9wb3BgKSkqMTAwKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoU3RhdGUsIGBGQl9QZW4yYCwgZmlsbCA9IHBlcmNlbnRGZW1hbGUpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikgKyBsYWJzKHRpdGxlID0gIkZhY2Vib29rIFBlbmV0cmF0aW9uIHdpdGggUmVzcGVjdCB0byBQZXJjZW50YWdlIG9mIEZlbWFsZSBQb3B1bGF0aW9uIiwgeT0iRmFjZWJvb2sgUGVuZXRyYXRpb24iKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfZyAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSAhPSAnRGlzdHJpY3Qgb2YgQ29sdW1iaWEnKSU+JSBkcGx5cjo6bXV0YXRlKHBlcmNlbnRNYWxlID0gKChgbWFsZV9wb3BgKS8oYHRvdGFsX3BvcGApKSoxMDApICU+JSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PVN0YXRlLCB5PXBlcmNlbnRNYWxlLCBncm91cCA9IDEpKSArIGdlb21fcG9pbnQoKSArIGdlb21fbGluZSgpICsgbGFicyh0aXRsZSA9ICJNYWxlIFBvcHVsYXRpb24gUGVyY2VudGFnZSBTcHJlYWQiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCg0KcmVuZGVyUGxvdCh7ZGZfZyAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSAhPSAnRGlzdHJpY3Qgb2YgQ29sdW1iaWEnKSU+JSBkcGx5cjo6bXV0YXRlKHBlcmNlbnRNYWxlID0gKChgbWFsZV9wb3BgKS8oYHRvdGFsX3BvcGApKSoxMDApICU+JSBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyhTdGF0ZSwgYEZCX1BlbjJgLCBmaWxsID0gcGVyY2VudE1hbGUpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikgKyBsYWJzKHRpdGxlID0gIkZhY2Vib29rIFBlbmV0cmF0aW9uIHdpdGggUmVzcGVjdCB0byBQZXJjZW50YWdlIG9mIE1hbGUgUG9wdWxhdGlvbiIsIHk9IkZhY2Vib29rIFBlbmV0cmF0aW9uIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQpgYGANCg0KKiogICAqKg0KIyMgKipZb3VuZ2VyIEFnZSBHcm91cCAoMTUtMjkpIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uKioNCg0KKipJbnB1dHRpbmcgdGhlIENTViBpbnRvIFIqKg0KDQpJbiB0aGlzIHN0ZXAsIEkgdXNlZCB0aGUgZGF0YS53b3JsZCBub24tc2VsZWN0ICogU1FMIHRvIGNyZWF0ZSB0d28gdGliYmxlcyBjb250YWluaW5nIGNvbHVtbnMgZnJvbSB0d28gZGlmZmVyZW50IGRhdGEgc291cmNlczogQWdlIGdyb3VwcyBvZiBwb3B1bGF0aW9uIGFuZCBGYWNlYm9vayBwZW5ldHJhdGlvbi4gVGhlIGNvZGUgZm9yIHRoaXMgaXMgc2hvd24gaW4gdGhlIHNjcmVlbnNob3QgYmVsb3cuDQoNCmBgYHtyfQ0KZGZfaCA8LSBkYXRhLndvcmxkOjpxdWVyeShkYXRhLndvcmxkOjpxcnlfc3FsDQooIlNFTEVDVCBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfZXN0aW1hdGVfYWdlXzE1X3RvXzE5X3llYXJzIGFzIGFnZTE1XzE5LA0KYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnRvdGFsX2VzdGltYXRlX2FnZV8yMF90b18yNF95ZWFycyBhcyBhZ2UyMF8yNCwNCmAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9lc3RpbWF0ZV9hZ2VfMjVfdG9fMjlfeWVhcnMgYXMgYWdlMjVfMjksDQpgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfcG9wdWxhdGlvbiBhcyB0b3RhbFBvcCwNCmZhY2Vib29rX2NsZWFuZWQuZmFjZWJvb2tfcGVuZXRyYXRpb24gYXMgRkJfUEVOLA0KYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiBhcyBTdGF0ZQ0KRlJPTSAyMDEycG9wdWxhdGlvbl9jbGVhbmVkDQpKT0lOIGZhY2Vib29rX2NsZWFuZWQgT04gYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnJlZ2lvbiA9IGZhY2Vib29rX2NsZWFuZWQucmVnaW9uIiksIGRhdGFzZXQ9cHJvamVjdCkNCmBgYA0KDQoqKlJlZm9ybWF0dGluZyBpbiBSKioNCg0KVGhlIG5leHQgc3RlcCBpbiB0aGUgZGF0YSBzY2llbmNlIHBpcGVsaW5lIGlzIHRvIGdhdGhlciB0aGUgY29sdW1ucyBpbnRvIGEgc2V0IG9mIGtleSB2YWx1ZSBwYWlycy4gSG93ZXZlciwgZm9yIHRoaXMgY3VycmVudCBpbnNpZ2h0LCBnYXRoZXJpbmcgd2FzIG5vdCBuZWVkZWQuDQoNCioqVXRpbGl6aW5nIGRwbHlyIHRvIHRyYW5zZm9ybSwgdmlzdWFsaXplLCBhbmQgY29tbXVuaWNhdGUqKg0KT25lIG9mIHRoZSBzdGVyZW90eXBlcyBpbiBzb2NpZXR5IGlzIHRoYXQgeW91bmdlciBwZW9wbGUgKHRlZW5hZ2VycyBhbmQgeW91bmcgYWR1bHRzKSBhcmUgbW9yZSB0ZWNoIHNhdnZ5IGFuZCBhcmUgYSB2YXN0IG1ham9yaXR5IG9mIHRoZSBzb2NpYWwgbWVkaWEgc2NlbmUuIEluIHRoaXMgaW5zaWdodCBJIGFtIGRlY2lkaW5nIHRvIHRlc3QgaWYgdGhlIHN0ZXJlb3R5cGUgaG9sZHMgYW55IHRydXRoLiBTcGVjaWZpY2FsbHksIEkgYW5hbHl6ZWQgRmFjZWJvb2sgcGVuZXRyYXRpb24gYW5kIGFnZSBncm91cCAxNS0yOS4gSSBjcmVhdGVkIGEgY2FsY3VsYXRlZCBmaWVsZCwgYnkgaW1wbGVtZW50aW5nIFIncyBtdXRhdGUgZnVuY3Rpb24sIHRvIGNvbmZpZ3VyZSB0aGUgcGVyY2VudGFnZSB0aGUgeW91bmdlciBjdXN0b20gYWdlIGdyb3VwIHRoYXQgSSBjcmVhdGVkLCByZXNwZWN0aXZlIHRvIHRoZSB0b3RhbCBwb3B1bGF0aW9uIHRvIGVhY2ggcmVzcGVjdGl2ZSBTdGF0ZS4gQXMgc2VlbiBwcmV2aW91c2x5LCBELkMuIHdhcyBhbiBpbW1lbnNlIG91dGxpZXIgYW5kIGhhZCB0aGUgaGlnaGVzdCBGYWNlYm9vayBwZW5ldHJhdGlvbiByZXNwZWN0aXZlIHRvIG90aGVyIFN0YXRlcy4gQmFzZWQgb24gdGhlIHBsb3QgYmVsb3csIEkgY2FuIGNvbmNsdWRlIHRoYXQgRC5DLiBoYXMgdGhlIG1vc3QgYW1vdW50IG9mIGluZGl2aWR1YWxzIHdpdGhpbiB0aGUgYWdlIGdyb3VwIDE1LTI5IHJlc3BlY3RpdmUgdG8gcG9wdWxhdGlvbiBzaW5jZSBpdCBoYWQgdGhlIGhpZ2hlc3QgIllvdW5nIEFnZSBHcm91cCwiIHBlcmNlbnRhZ2UgY29tcGFyZWQgdG8gb3RoZXIgc3RhdGVzLCB0aHVzIGV4ZW1wbGlmeWluZyBzYWlkIHN0ZXJlb3R5cGUuDQoNCmBgYHtyfQ0KcmVuZGVyUGxvdCh7ZGZfaCAlPiUgZHBseXI6OmZpbHRlcihTdGF0ZSAhPSAnVW5pdGVkIFN0YXRlcycpJT4lIGRwbHlyOjptdXRhdGUoeW91bmdlciA9ICgoYGFnZTE1XzE5YCArIGBhZ2UyMF8yNGAgKyBgYWdlMjVfMjlgKS8oYHRvdGFsUG9wYCkpKjEwMCkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKFN0YXRlLCB5b3VuZ2VyKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJQb3B1bGF0aW9uIFBlcmNlbnRhZ2Ugb2YgQ3VzdG9tIEFnZSBHcm91cCAoMTUtMjkpIGJ5IFN0YXRlIiwgeT0iUGVyY2VudGFnZSBvZiBBZ2UgR3JvdXAgMTUtMjkiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCmBgYA0KDQpFeGFtaW5pbmcgdGhlIHlvdW5nZXIgYWdlIGdyb3VwLCB3ZSBzZWUgdGhhdCB0aGUgdG9wIDUgU3RhdGVzIHdpdGggdGhlIGhpZ2hlc3QgcGVyY2VudGFnZSBvZiBhZ2VzIDE1LTI5LCBhcmUgRC5DLiwgV3lvbWluZywgTm9ydGggRGFrb3RhLCBWZXJtb250LCBhbmQgQWxhc2thLiBJbnRlcmVzdGluZyBlbm91Z2ggd2Ugc2VlIHRoYXQgYW1vbmcgdGhlIHNldCBvZiBzdGF0ZXMsIG9ubHkgREMgaXMgYXBhcnQgb2YgdGhlIHRvcCA1IEZhY2Vib29rIHBlbmV0cmF0aW9uIFN0YXRlcy4NCg0KYGBge3J9DQpyZW5kZXJQbG90KHtkZl9oICU+JSBkcGx5cjo6IGZpbHRlcihTdGF0ZSAlaW4lIGMoIkFsYXNrYSIsICJEaXN0cmljdCBvZiBDb2x1bWJpYSIsICJOb3J0aCBEYWtvdGEiLCAiVmVybW9udCIsICJXeW9taW5nIikpJT4lIGRwbHlyOjptdXRhdGUoeW91bmdlciA9ICgoYGFnZTE1XzE5YCArIGBhZ2UyMF8yNGAgKyBgYWdlMjVfMjlgKS8oYHRvdGFsUG9wYCkpKjEwMCkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKFN0YXRlLCB5b3VuZ2VyLCBmaWxsID0gIiNGRjY2NjYiKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJUaGUgRml2ZSBIaWdoZXN0IFBvcHVsYXRpb24gUGVyY2VudGFnZSBvZiBBZ2UgR3JvdXAgKDE1LTI5KSIsIHk9IlBlcmNlbnRhZ2Ugb2YgQWdlIEdyb3VwIDE1LTI5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQpgYGANCg0KV2UgYW5hbHl6aW5nIGZ1cnRoZXIgYnkgaW5jb3Jwb3JhdGluZyBGYWNlYm9vayBwZW5ldHJhdGlvbiBkaXJlY3RseSBpbnRvIG91ciBkYXRhIGFuYWx5c2lzLiBHaXZlbiB0aGF0IHRoZSBEaXN0cmljdCBvZiBDb2x1bWJpYSBpcyBhbiBleHRyZW1lIG91dGxpZXIsIHdlIGV4dHJhcG9sYXRlIGl0IGFuZCBmdXJ0aGVyIGFuYWx5emUgRmFjZWJvb2sgcGVuZXRyYXRpb24gd2l0aCByZXNwZWN0IHRvIHRoZSB5b3VuZ2VyIGFnZSBncm91cCBvZiAxNS0yOS4gQmFzZWQgb24gdGhlIHNjcmVlbnNob3QgYmVsb3csIHdlIG5vdyByZWFsaXplIHRoYXQgYWx0aG91Z2ggb25seSBEQyB3YXMgYXBhcnQgb2YgdGhlIHRvcCA1IEZhY2Vib29rIHBlbmV0cmF0aW9uIFN0YXRlcywgdGhlIHRvcCA0IFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IHBlcmNlbnRhZ2Ugb2YgYWdlcyAxNS0yOSBoYXZlIGhpZ2ggRmFjZWJvb2sgcGVuZXRyYXRpb24gYXMgd2VsbCwganVzdCBub3QgdGhlIGhpZ2hlc3QuIFRodXMgb25lIGNhbiBjb25jbHVkZSB0aGF0IGFnZSBpcyBhIGZhY3RvciB3aGVuIGl0IGNvbWVzIHRvIHRoZSBzb2NpYWwgbWVkaWEgc2NlbmUsIGp1c3Qgbm90IGFzIG92ZXJ3aGVsbWluZyBhcyBpdCBpcyBwb3J0cmF5ZWQgaW4gc29jaWV0eS4NCg0KYGBge3J9DQpyZW5kZXJQbG90KHtkZl9oICU+JSBkcGx5cjo6IGZpbHRlcihTdGF0ZSAhPSAiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiKSAlPiUgZHBseXI6Om11dGF0ZSh5b3VuZ2VyID0gKChgYWdlMTVfMTlgICsgYGFnZTIwXzI0YCArIGBhZ2UyNV8yOWApLyhgdG90YWxQb3BgKSkqMTAwKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2JhcihhZXMoU3RhdGUsIHlvdW5nZXIsIGZpbGwgPSBgRkJfUEVOYCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArIGxhYnModGl0bGUgPSAiRmFjZWJvb2sgUGVuZXRyYXRpb24gd2l0aCBSZXNwZWN0IHRvIFBvcHVsYXRpb24gUGVyY2VudGFnZSBvZiBDdXN0b20gQWdlIEdyb3VwICgxNS0yOSkiLCB5PSJQZXJjZW50YWdlIG9mIEFnZSBHcm91cCAxNS0yOSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSl9KQ0KDQpgYGANCg0KSW52ZXN0aWdhdGluZyBmdXJ0aGVyLCBpdCBpcyBleHRyZW1lbHkgb2RkLCBhbmQgaW50ZXJlc3RpbmcgdG8gc2VlIHRoYXQgR2VvcmdpYSwgSWxsaW5vaXMsIGFuZCBXYXNoaW5ndG9uIChwYXJ0IG9mIHRoZSBUb3AgNSBGYWNlYm9vayBwZW5ldHJhdGlvbiBTdGF0ZXMpLCBoYWQgZXh0cmVtZWx5IGxvdyBwZXJjZW50YWdlcyBvZiBhZ2VzIDE1LTI5IHJlc3BlY3RpdmUgdG8gZWFjaCBTdGF0ZSdzIHBvcHVsYXRpb24uIFNpbWlsYXJseSwgaXQgaXMgb2RkIHRvIHNlZSB0aGF0IERlbGF3YXJlLCB0aGUgU3RhdGUgd2l0aCB0aGUgbG93ZXN0LCBGYWNlYm9vayBwZW5ldHJhdGlvbiwgYXMgbWVudGlvbmVkIHByZXZpb3VzbHksIGhhcyBhIHByZXR0eSBoaWdoIHBlcmNlbnRhZ2Ugb2YgYWdlIDE1LTI5IGluZGl2aWR1YWxzLiBCb3RoIG9mIHRoZXNlIGFmb3JlbWVudGlvbmVkIGRldGFpbHMgYXJlIGNvdW50ZXIgaW50dWl0aXZlIHRvIHdoYXQgdGhlIGRhdGEgaGFzIHNob3duIHVwIHVudGlsIG5vdy4gVGhpcyBjb3VsZCBtZWFuIHRoYXQgdGhlcmUgYXJlIGJpZ2dlciB2YXJpYWJsZXMgYXQgcGxheSBlZmZlY3RpbmcgRmFjZWJvb2sgcGVuZXRyYXRpb24gb3IgdGhlc2UgYXJlIG1lcmVseSBleGNlcHRpb25zIG9yIGFnZSBpcyBub3QgYXMgYmlnIG9mIGEgZmFjdG9yIGFzIGltYWdpbmVkLg0KDQpgYGB7cn0NCnJlbmRlclBsb3Qoe2RmX2ggJT4lIGRwbHlyOjogZmlsdGVyKFN0YXRlICVpbiUgYygiRGVsYXdhcmUiLCAiR2VvcmdpYSIsICJJbGxpbm9pcyIsICJXYXNoaW5ndG9uIikpICU+JSBkcGx5cjo6bXV0YXRlKHlvdW5nZXIgPSAoKGBhZ2UxNV8xOWAgKyBgYWdlMjBfMjRgICsgYGFnZTI1XzI5YCkvKGB0b3RhbFBvcGApKSoxMDApICU+JSBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyhTdGF0ZSwgeW91bmdlciwgZmlsbCA9IGBGQl9QRU5gKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJGYWNlYm9vayBQZW5ldHJhdGlvbiB3aXRoIFJlc3BlY3QgdG8gUG9wdWxhdGlvbiBQZXJjZW50YWdlIG9mIEN1c3RvbSBBZ2UgR3JvdXAgKDE1LTI5KSIsIHk9IlBlcmNlbnRhZ2Ugb2YgQWdlIEdyb3VwIDE1LTI5IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQpgYGANCioqICAgKioNCiMjICoqRWxkZXJseSBBZ2UgR3JvdXAgKDYwLTg1KykgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24qKg0KDQoqKklucHV0dGluZyB0aGUgQ1NWIGludG8gUioqDQoNCkluIHRoaXMgc3RlcCwgSSB1c2VkIHRoZSBkYXRhLndvcmxkIG5vbi1zZWxlY3QgKiBTUUwgdG8gY3JlYXRlIHR3byB0aWJibGVzIGNvbnRhaW5pbmcgY29sdW1ucyBmcm9tIHR3byBkaWZmZXJlbnQgZGF0YSBzb3VyY2VzOiBBZ2UgZ3JvdXBzIG9mIHBvcHVsYXRpb24gYW5kIEZhY2Vib29rIHBlbmV0cmF0aW9uLiBUaGUgY29kZSBmb3IgdGhpcyBpcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCBiZWxvdy4NCg0KYGBge3J9DQpkZl9pIDwtIGRhdGEud29ybGQ6OnF1ZXJ5KGRhdGEud29ybGQ6OnFyeV9zcWwNCigiU0VMRUNUIGAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9lc3RpbWF0ZV9hZ2VfNjBfdG9fNjRfeWVhcnMgYXMgYWdlNjBfNjQsDQpgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAudG90YWxfZXN0aW1hdGVfYWdlXzY1X3RvXzY5X3llYXJzIGFzIGFnZTY1XzY5LA0KYDIwMTJwb3B1bGF0aW9uX2NsZWFuZWRgLnRvdGFsX2VzdGltYXRlX2FnZV83MF90b183NF95ZWFycyBhcyBhZ2U3MF83NCwNCmAyMDEycG9wdWxhdGlvbl9jbGVhbmVkYC50b3RhbF9wb3B1bGF0aW9uIGFzIHRvdGFsUE9QLA0KZmFjZWJvb2tfY2xlYW5lZC5mYWNlYm9va19wZW5ldHJhdGlvbiBhcyBGQl9wZW4sDQpgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uIGFzIFN0YXRlDQpGUk9NIDIwMTJwb3B1bGF0aW9uX2NsZWFuZWQNCkpPSU4gZmFjZWJvb2tfY2xlYW5lZCBPTiBgMjAxMnBvcHVsYXRpb25fY2xlYW5lZGAucmVnaW9uID0gZmFjZWJvb2tfY2xlYW5lZC5yZWdpb24NCiIpLCBkYXRhc2V0PXByb2plY3QpDQpgYGANCg0KKipSZWZvcm1hdHRpbmcgaW4gUioqDQoNClRoZSBuZXh0IHN0ZXAgaW4gdGhlIGRhdGEgc2NpZW5jZSBwaXBlbGluZSBpcyB0byBnYXRoZXIgdGhlIGNvbHVtbnMgaW50byBhIHNldCBvZiBrZXkgdmFsdWUgcGFpcnMuIEhvd2V2ZXIsIGZvciB0aGlzIGN1cnJlbnQgaW5zaWdodCwgZ2F0aGVyaW5nIHdhcyBub3QgbmVlZGVkLg0KDQoqKlV0aWxpemluZyBkcGx5ciB0byB0cmFuc2Zvcm0sIHZpc3VhbGl6ZSwgYW5kIGNvbW11bmljYXRlKioNCg0KSGF2aW5nIGFuYWx5emVkIGFuZCBzb21ld2hhdCB2YWxpZGF0ZWQgdGhhdCB0aGUgbWFqb3JpdHkgb2Ygc29jaWFsIG1lZGlhIHVzZXJzIGFyZSBhbW9uZyB0aGUgeW91bmdlciBhZ2UgZ3JvdXBzLCBJIGFuYWx5emUgdGhlIGVsZGVyIGFnZSBncm91cCB0byBjaGVjayBpZiBpdCBtYXRjaGVzIHRoZSBvdXRjb21lIGFuZCB0byB0ZXN0IHRoZSBhbHRlcm5hdGl2ZSBzdGVyZW90eXBlIHRoYXQgZWxkZXJseSBtYWtlIHVwIHRoZSB2YXN0IG1pbm9yaXR5IG9mIHNvY2lhbCBtZWRpYSB1c2Vycy4gSSBjcmVhdGUgYSBjYWxjdWxhdGVkIGZpZWxkLCBieSBpbXBsZW1lbnRpbmcgUidzIG11dGF0ZSBmdW5jdGlvbiB0byB0aGF0IGNhbGN1bGF0ZXMgdGhlIHBlcmNlbnRhZ2Ugb2YgZWxkZXJzIDYwLTg1KyB5ZWFycyBvZiBhZ2UgcmVzcGVjdGl2ZSB0byBwb3B1bGF0aW9uIHBlciBTdGF0ZS4gQXQgaW5pdGlhbCBnbGFuY2UsIEkgc2VlIHRoYXQgRC5DLiBpcyBub3QgYW1vbmcgdGhlIHRvcCAzIFN0YXRlcyB3aXRoIHRoZSBsYXJnZXN0IHBlcmNlbnRhZ2Ugb2YgYWdlcyA2MC04NSsgaW5kaXZpZHVhbHMsIHRoaXMgaXMgZXhwZWN0ZWQgYXMgdGhlIFN0YXRlIHdpdGggdGhlIGhpZ2hlc3QgRmFjZWJvb2sgcGVuZXRyYXRpb24gc2hvdWxkIGhhdmUgbW9yZSB5b3VuZ2VyIHBvcHVsYXRpb24gaWYgdGhlIHN0ZXJlb3R5cGVzIGFyZSB0cnVlLg0KDQpgYGB7cn0NCnJlbmRlclBsb3Qoe2RmX2kgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgIT0gJ0Rpc3RyaWN0IG9mIENvbHVtYmlhJyklPiUgZHBseXI6Om11dGF0ZShlbGRlciA9ICgoYGFnZTYwXzY0YCArIGBhZ2U2NV82OWAgKyBgYWdlNzBfNzRgKS8oYHRvdGFsUE9QYCkpKjEwMCkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKFN0YXRlLCBlbGRlciwgZmlsbCA9IGBGQl9wZW5gKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJGYWNlYm9vayBQZW5ldHJhdGlvbiB3aXRoIFJlc3BlY3QgdG8gUG9wdWxhdGlvbiBQZXJjZW50YWdlIG9mIEN1c3RvbSBBZ2UgR3JvdXAgKDYwLTg1KykgYnkgU3RhdGUiLCB5PSJQZXJjZW50YWdlIG9mIEFnZSBHcm91cCA2MC04NSsiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpfSkNCmBgYA0KDQpBZnRlciBleHRyYXBvbGF0aW5nIHRoZSBvdXRsaWVyIERDLCBJIGltcGxlbWVudCBhIHRyZWUgbWFwIHRvIGdhaW4gbW9yZSBwZXJzcGVjdGl2ZS4gSSB0aGF0IHRoZSBzaXggU3RhdGVzIHdpdGggdGhlIGhpZ2hlc3QgcGVyY2VudGFnZSA2MC04NSsgcG9wdWxhdGlvbiAocmFua2VkIGJ5IHNpemUpLCBhcmUgVmVybW9udCwgV3lvbWluZywgTm9ydGggRGFrb3RhLCBTb3V0aCBEYWtvdGEsIERlbGF3YXJlLCBhbmQgTW9udGFuYS4gT2YgdGhlIHNpeCBTdGF0ZXMsIGZvdXIgb2Ygd2hpY2ggaGF2ZSBsb3dlciBGYWNlYm9vayBwZW5ldHJhdGlvbiwgd2l0aCBXeW9taW5nIGFuZCBOb3J0aCBEYWtvdGEgYmVpbmcgZXhjZXB0aW9ucy4gTW9zdCBpbXBvcnRhbnRseSwgd2Ugc2VlIHRoYXQgRGVsYXdhcmUsIHRoZSBTdGF0ZSB3aXRoIHRoZSBhYnNvbHV0ZSBsb3dlc3QgRmFjZWJvb2sgcGVuZXRyYXRpb24gaXMgYW1vbmcgdGhlIFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IHBlcmNlbnRhZ2Ugb2YgZWxkZXJseSBwb3B1bGF0aW9uICg2MC04NSsgeWVhcnMgb2YgYWdlKSwgdGh1cyB2YWxpZGF0aW5nIG91ciBwcmV2aW91cyBvdXRjb21lIG9uIHRoZSB5b3VuZ2VyIGFnZSBncm91cC4gVGFraW5nIGEgbG9vayBhdCB0aGUgZGlzdHJpYnV0ZWQgcGF0dGVybiBvZiBGYWNlYm9vayBwZW5ldHJhdGlvbiByZWxhdGl2ZSB0byB0aGUgZWxkZXJseSBhZ2UgdHJlZSBtYXAsIHdlIHNlZSB0aGF0IHRoZSB2YXN0IG1ham9yaXR5IG9mIGhpZ2ggRmFjZWJvb2sgcGVuZXRyYXRpb24gYXJlIGFtb25nIHRoZSBzbWFsbGVyIHNpemVkIHRpbGVzIGluZGljYXRpbmcsIFN0YXRlcyB3aXRoIG11Y2ggbG93ZXIgcGVyY2VudGFnZXMgb2YgZWxkZXJseSBwb3B1bGF0aW9uIGhhdmUgaGlnaGVyIEZhY2Vib29rIHBlbmV0cmF0aW9uLCB0aHVzIGV4ZW1wbGlmeWluZyB0aGUgc3RlcmVvdHlwZSBhcyB3ZWxsLiBDb25zZXF1ZW50bHksIG9uZSBjYW4gY29uY2x1ZGUsIHRoYXQgYWdlIGRvZXMgcGxheSBhIHNpZ25pZmljYW50IGZhY3RvciBpbiBGYWNlYm9vayBwZW5ldHJhdGlvbiwgc29jaWFsIG1lZGlhIHVzYWdlLiBIb3dldmVyLCB3ZSBhZ2FpbiBzZWUgc29tZSBvZGRpdGllcyBpbiBvdXIgZGF0YS4gV2Ugc2VlIHRoYXQgV3lvbWluZyBhbmQgTm9ydGggRGFrb3RhIGhhdmUgcHJldHR5IGhpZ2ggRmFjZWJvb2sgcGVuZXRyYXRpb24sIGJ1dCBhcmUgcGFydCBvZiB0aGUgU3RhdGVzIHdpdGggdGhlIGxhcmdlc3QgZWxkZXJseSBwb3B1bGF0aW9uLCB0aHVzIHNpZ25pZnlpbmcgdGhhdCB0aGVyZSBhcmUgb3RoZXIgdmFyaWFibGVzIGF0IHBsYXkgYXMgd2VsbC4NCg0KYGBge3J9DQpyZW5kZXJQbG90KHsNCiBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YT1kZl9pICU+JSBkcGx5cjo6bXV0YXRlKGVsZGVyID0gKChgYWdlNjBfNjRgICsgYGFnZTY1XzY5YCArIGBhZ2U3MF83NGApLyhgdG90YWxQT1BgKSkqMTAwKSAlPiUgYXJyYW5nZShlbGRlcikgJT4lIGRwbHlyOjpmaWx0ZXIoU3RhdGUgIT0gJ0Rpc3RyaWN0IG9mIENvbHVtYmlhJyksIG1hcHBpbmcgPSBhZXMoYXJlYSA9IGVsZGVyLCBmaWxsID0gRkJfcGVuLCBsYWJlbD1TdGF0ZSkpICsNCiBnZW9tX3RyZWVtYXAoKSArDQogZ2VvbV90cmVlbWFwX3RleHQoZm9udGZhY2UgPSAiaXRhbGljIiwgY29sb3VyID0gIndoaXRlIiwgcGxhY2UgPSAidG9wbGVmdCIpKyBsYWJzKHRpdGxlID0gIlRyZWUgTWFwIG9mIFBvcHVsYXRpb24gb2YgRWxkZXIgQWdlIEdyb3VwICg2MC04NSspIFJlbGF0aXZlIHRvIEZhY2Vib29rIFBlbmV0cmF0aW9uIChmaWxsID0gRmFjZWJvb2sgUGVuZXRyYXRpb24sIGFyZWEgPSBQb3B1bGF0aW9uIFBlcmNlbnRhZ2Ugb2YgQWdlIEdyb3VwIDYwLTg1KyIpDQp9KQ0KDQpyZW5kZXJQbG90KHtkZl9pICU+JSBkcGx5cjo6IGZpbHRlcihTdGF0ZSAlaW4lIGMoIlZlcm1vbnQiLCAiU291dGggRGFrb3RhIiwgIk5vcnRoIERha290YSIsICJEZWxhd2FyZSIsICJXeW9taW5nIiwgIk1vbnRhbmEiKSklPiUgZHBseXI6Om11dGF0ZShlbGRlciA9ICgoYGFnZTYwXzY0YCArIGBhZ2U2NV82OWAgKyBgYWdlNzBfNzRgKS8oYHRvdGFsUE9QYCkpKjEwMCkgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKFN0YXRlLCBlbGRlciwgZmlsbCA9IGBGQl9wZW5gKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJUaGUgU2l4IExvd2VzdCBQb3B1bGF0aW9uIFBlcmNlbnRhZ2Ugb2YgQWdlIEdyb3VwICg2MC04NSspIiwgeT0iUGVyY2VudGFnZSBvZiBBZ2UgR3JvdXAgNjAtODUrIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKX0pDQoNCmBgYA0KDQojICoqQXBwZW5kaXgqKg0KDQoxKQlBZXMg4oCTIGZvdW5kIGluIGV2ZXJ5IGluc2lnaHQNCjIpCUFycmFuZ2Ug4oCTIA0KICAgIEEpCUxldmVscyBvZiBJbnRlcm5ldCBVc2FnZSBieSBTdGF0ZSBhbmQgQXZlcmFnZSBJbmNvbWUgYnkgU3RhdGUgZm9yIHRoZSBZZWFycyAyMDA3LzIwMTINCiAgICAgICAgQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYW5kIEludGVybmV0IFBlbmV0cmF0aW9uDQogICAgQikJUmVsYXRpb25zaGlwIEJldHdlZW4gSW5jb21lIGFuZCBVc2VycyBBY2Nlc3NpbmcgSW50ZXJuZXQgT3V0c2lkZSBIb21lIGZyb20gMjAwNyB0byAyMDEyDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2Ug4oCTIDIwMDcNCiAgICAgICAgUmVsYXRpb25zaGlwIEJldHdlZW4gRmFjZWJvb2sgUGVuZXRyYXRpb24sIEludGVybmV0IFBlbmV0cmF0aW9uLCBhbmQgMjAtMjQgUG9wdWxhdGlvbiDigJMgMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgYmV0d2VlbiBJbi1ob21lIGFuZCBPdXQgb2YgSG9tZSBJbnRlcm5ldCBBY2Nlc3MgZm9yIDIwMDcvMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYXhpbXVtIERpc2NyZXBhbmN5IG9mIEludGVybmV0IEFjY2VzcyBPdXRzaWRlIEhvdXNlaG9sZCBhbmQgSW5jb21lIEJyYWNrZXRzDQogICAgQykgIEVsZGVybHkgQWdlIEdyb3VwICg2MC04NSspIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQozKQlCYXIgQ2hhcnQNCiAgICBBKQlMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgICAgIERpZmZlcmVuY2UgaW4gSW5jb21lIGJ5IFN0YXRlIGZvciAyMDA3LTIwMTINCiAgICAgICAgRmFjZWJvb2sgUGVuZXRyYXRpb24gZm9yIDE1LTE5IFllYXIgT2xkcyBWZXJzdXMgNDAtNDQgWWVhciBPbGRzDQogICAgICAgIFBlcmNlbnQgb2YgSW5kaXZpZHVhbHMgV2hvIEFjY2Vzc2VkIHRoZSBJbnRlcm5ldCBmcm9tIEhvbWUgaW4gMjAwNyBhbmQgMjAxMg0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1pbGxlbm5pYWwgUG9wdWxhdGlvbiBhbmQgSW50ZXJuZXQgQWNjZXNzDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1pbGxlbm5pYWwgUG9wdWxhdGlvbiBhbmQgSW50ZXJuZXQgQWNjZXNzDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIOKAkyAyMDA3DQogICAgQykJVHJlbmRzIGluIHBlcmNlbnQgY2hhbmdlcyBiZXR3ZWVuIDIwMDcgYW5kIDIwMTIgYnkgc3RhdGUgb2YgaG91c2Vob2xkIGluY29tZSBhbmQgaG9tZSBpbnRlcm5ldCB1c2FnZQ0KICAgICAgICBGYWNlYm9vayB1c2VycyB2cyBtb2RlIG9mIEludGVybmV0IHVzYWdlIGluIDIwMDcNCiAgICAgICAgRmFjZWJvb2sgdXNlcnMgdnMgbW9kZSBvZiBJbnRlcm5ldCB1c2FnZSBpbiAyMDEyDQogICAgRCApIEdlbmRlciBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg0KICAgICAgICBZb3VuZ2VyIEFnZSBHcm91cCAoMTUtMjkpIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQogICAgICAgIEVsZGVybHkgQWdlIEdyb3VwICg2MC04NSspIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQo0KQlCbGVuZGluZyBEYXRhDQogICAgQSkJQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYW5kIEludGVybmV0IFBlbmV0cmF0aW9uDQogICAgQikJUmVsYXRpb25zaGlwIGJldHdlZW4gTWFsZSB0byBGZW1hbGUgUmF0aW8gYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIChCbGVuZGluZyBEYXRhICsgSWZlbHNlICsgTE9EICkNCjUpCUJveCBQbG90DQogICAgQSkJRGlmZmVyZW5jZSBpbiBJbmNvbWUgYnkgU3RhdGUgZm9yIDIwMDctMjAxMg0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2Ug4oCTIDIwMDcNCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gTWFsZSB0byBGZW1hbGUgUmF0aW8gYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIChCbGVuZGluZyBEYXRhICsgSWZlbHNlICsgTE9EICkNCjYpCUNhbGN1bGF0ZWQgZmllbGRzDQogICAgQSkJTGV2ZWxzIG9mIEludGVybmV0IFVzYWdlIGJ5IFN0YXRlIGFuZCBBdmVyYWdlIEluY29tZSBieSBTdGF0ZSBmb3IgdGhlIFllYXJzIDIwMDcvMjAxMg0KICAgIEIpCVJlbGF0aW9uc2hpcCBiZXR3ZWVuIE1hbGUgdG8gRmVtYWxlIFJhdGlvIGFuZCBJbnRlcm5ldCBQZW5ldHJhdGlvbiAoQmxlbmRpbmcgRGF0YSArIElmZWxzZSArIExPRCkNCiAgICAgICAgUmVsYXRpb25zaGlwIEJldHdlZW4gSW5jb21lIGFuZCBVc2VycyBBY2Nlc3NpbmcgSW50ZXJuZXQgT3V0c2lkZSBIb21lIGZyb20gMjAwNyB0byAyMDEyDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2Ug4oCTIDIwMDcNCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gSW4taG9tZSBhbmQgT3V0IG9mIEhvbWUgSW50ZXJuZXQgQWNjZXNzIGZvciAyMDA3LzIwMTINCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gTWF4aW11bSBEaXNjcmVwYW5jeSBvZiBJbnRlcm5ldCBBY2Nlc3MgT3V0c2lkZSBIb3VzZWhvbGQgYW5kIEluY29tZSBCcmFja2V0cw0KICAgIEMpIEludGVybmV0IEFjY2VzcyBWcyBBdmVyYWdlIEluY29tZSBSZXNwZWN0aXZlIHRvIDIwMDcgYW5kIDIwMTINCiAgICAgICBHZW5kZXIgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24NCiAgICAgICBZb3VuZ2VyIEFnZSBHcm91cCAoMTUtMjkpIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQogICAgICAgRWxkZXJseSBBZ2UgR3JvdXAgKDYwLTg1KykgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24NCjcpCUNhc2UNCiAgICBBKQlMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIEJldHdlZW4gRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIEhvdXNlaG9sZCBJbnRlcm5ldCBVc2FnZSDigJMgMjAwNw0KICAgICAgICBSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYXhpbXVtIERpc2NyZXBhbmN5IG9mIEludGVybmV0IEFjY2VzcyBPdXRzaWRlIEhvdXNlaG9sZCBhbmQgSW5jb21lIEJyYWNrZXRzDQo4KQlDbGVhbmluZyBkYXRhDQogICAgQSkJSW5wdXR0aW5nIGFuZCBDbGVhbmluZyB0aGUgQ1NWcw0KOSkJQ3Jvc3N0YWINCiAgICBBKQlMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIEJldHdlZW4gSW5jb21lIGFuZCBVc2VycyBBY2Nlc3NpbmcgSW50ZXJuZXQgT3V0c2lkZSBIb21lIGZyb20gMjAwNyB0byAyMDEyDQoxMCkJRGFzaGJvYXJkDQogICAgQSkJSW50ZXJuZXQgVXNhZ2UgYXQgSG9tZSBhbmQgaXRzIENvcnJlbGF0aW9uIHdpdGggdGhlIDY1LTY5IFllYXIgT2xkIFBvcHVsYXRpb24NCiAgICBCKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBNaWxsZW5uaWFsIFBvcHVsYXRpb24gYW5kIEludGVybmV0IEFjY2Vzcw0KMTEpCURhdGEgTW9kZWwNCiAgICBBKQlCdWlsZGluZyB0aGUgRGF0YSBNb2RlbA0KMTIpCUZhY2V0IHdyYXANCiAgICBBKQlEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIGJldHdlZW4gTWF4aW11bSBEaXNjcmVwYW5jeSBvZiBJbnRlcm5ldCBBY2Nlc3MgT3V0c2lkZSBIb3VzZWhvbGQgYW5kIEluY29tZSBCcmFja2V0cw0KICAgICAgICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIC0gMjAwNw0KMTMpCUZpbHRlcg0KICAgIEEpCURpZmZlcmVuY2UgaW4gSW5jb21lIGJ5IFN0YXRlIGZvciAyMDA3LTIwMTINCiAgICAgICAgRmFjZWJvb2sgUGVuZXRyYXRpb24gZm9yIDE1LTE5IFllYXIgT2xkcyBWZXJzdXMgNDAtNDQgWWVhciBPbGRzDQogICAgICAgIFBlcmNlbnQgb2YgSW5kaXZpZHVhbHMgV2hvIEFjY2Vzc2VkIHRoZSBJbnRlcm5ldCBmcm9tIEhvbWUgaW4gMjAwNyBhbmQgMjAxMg0KICAgICAgICBMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgICAgIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBpdHMgUmVsYXRpb25zaGlwIHRvIEF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZQ0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1pbGxlbm5pYWwgUG9wdWxhdGlvbiBhbmQgSW50ZXJuZXQgQWNjZXNzDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIOKAkyAyMDA3DQogICAgICAgIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIEluLWhvbWUgYW5kIE91dCBvZiBIb21lIEludGVybmV0IEFjY2VzcyBmb3IgMjAwNy8yMDEyDQogICAgQykJRmFjZWJvb2sgdXNlcnMgdnMgbW9kZSBvZiBJbnRlcm5ldCB1c2FnZSBpbiAyMDA3DQogICAgICAgIEZhY2Vib29rIHVzZXJzIHZzIG1vZGUgb2YgSW50ZXJuZXQgdXNhZ2UgaW4gMjAxMg0KICAgIEQpICBHZW5kZXIgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24NCiAgICAgICAgWW91bmdlciBBZ2UgR3JvdXAgKDE1LTI5KSBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg0KICAgICAgICBFbGRlcmx5IEFnZSBHcm91cCAoNjAtODUrKSBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg0KMTQpCUdhdGhlcg0KICAgIEEpCVBlcmNlbnQgb2YgSW5kaXZpZHVhbHMgV2hvIEFjY2Vzc2VkIHRoZSBJbnRlcm5ldCBmcm9tIEhvbWUgaW4gMjAwNyBhbmQgMjAxMg0KICAgICAgICBEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgQikgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgYmV0d2VlbiBJbi1ob21lIGFuZCBPdXQgb2YgSG9tZSBJbnRlcm5ldCBBY2Nlc3MgZm9yIDIwMDcvMjAxMg0KMTUpCUdlb20g4oCTIGZvdW5kIGluIGV2ZXJ5IGluc2lnaHQNCjE2KQlHcm91cCBCeSAoU1FMKQ0KICAgIEEpCVJlbGF0aW9uc2hpcCBiZXR3ZWVuIEluLWhvbWUgYW5kIE91dCBvZiBIb21lIEludGVybmV0IEFjY2VzcyBmb3IgMjAwNy8yMDEyDQoxNykJR3JvdXBfQnkgKGRwbHlyKQ0KICAgIEEpCURpZmZlcmVuY2UgaW4gSW5jb21lIGJ5IFN0YXRlIGZvciAyMDA3LTIwMTINCiAgICBCKQlSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYWxlIHRvIEZlbWFsZSBSYXRpbyBhbmQgSW50ZXJuZXQgUGVuZXRyYXRpb24gKEJsZW5kaW5nIERhdGEgKyBJZmVsc2UgKyBMT0QgKQ0KMTgpCUhpc3RvZ3JhbQ0KICAgIEEpCUZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBpdHMgUmVsYXRpb25zaGlwIHRvIEF2ZXJhZ2UgSG91c2Vob2xkIEluY29tZQ0KICAgIEIpICBJbnRlcm5ldCBQZW5ldHJhdGlvbiBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbiBWcyBJbnRlcm5ldCBBY2Nlc3MNCjE5KQlKb2luIChTUUwpDQogICAgQSkJRnVsbA0KICAgICAgICBhKQlEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgQikJTGVmdA0KICAgICAgICBhKQlQZXJjZW50IG9mIEluZGl2aWR1YWxzIFdobyBBY2Nlc3NlZCBUaGUgSW50ZXJuZXQgZnJvbSBIb21lIGluIDIwMDcgYW5kIDIwMTINCiAgICAgICAgYikJUmVsYXRpb25zaGlwIEJldHdlZW4gRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIEhvdXNlaG9sZCBJbnRlcm5ldCBVc2FnZSAtIDIwMDcNCiAgICBDKQlSaWdodA0KICAgICAgICBhKQlSZWxhdGlvbnNoaXAgYmV0d2VlbiBJbi1ob21lIGFuZCBPdXQgb2YgSG9tZSBJbnRlcm5ldCBBY2Nlc3MgZm9yIDIwMDcvMjAxMg0KMjApCUpvaW5pbmcgVGFibGVzIOKAkyBmb3VuZCBpbiBldmVyeSBpbnNpZ2h0DQoyMSkJSm9pbmluZyB0byBDZW5zdXMgZGF0YSDigJMgZm91bmQgaW4gZXZlcnkgaW5zaWdodA0KMjIpCUxldmVsIG9mIERldGFpbCBDYWxjdWxhdGlvbnMNCiAgICBBKQlEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIGJldHdlZW4gTWFsZSB0byBGZW1hbGUgUmF0aW8gYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIChCbGVuZGluZyBEYXRhICsgSWZlbHNlICsgTE9EKQ0KMjMpCU1hcHMgKENob3JvcGxldGgpDQogICAgQSkJRGlmZmVyZW5jZSBpbiBJbmNvbWUgYnkgU3RhdGUgZm9yIDIwMDctMjAxMg0KICAgICAgICBJbnRlcm5ldCBVc2FnZSBhdCBIb21lIGFuZCBpdHMgQ29ycmVsYXRpb24gd2l0aCB0aGUgNjUtNjktWWVhci1PbGQgUG9wdWxhdGlvbg0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KYikJUmVsYXRpb25zaGlwIGJldHdlZW4gTWFsZSB0byBGZW1hbGUgUmF0aW8gYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIChCbGVuZGluZyBEYXRhICsgSWZlbHNlICsgTE9EICkNCjI0KQlNdXRhdGUNCiAgICBBKQlDdW11bGF0aXZlIERpc3RyaWJ1dGlvbg0KICAgICAgICBhKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIC0gMjAwNw0KICAgIEIpCUN1bXVsYXRpdmUgTWVhbg0KICAgICAgICBhKQlGYWNlYm9vayB1c2VycyB2cyBtb2RlIG9mIEludGVybmV0IHVzYWdlIGluIDIwMDcNCiAgICBDKQlDdW11bGF0aXZlIFN1bQ0KICAgICAgICBhKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIC0gMjAwNw0KICAgIEQpCUlmIEVsc2UNCiAgICAgICAgYSkJTGV2ZWxzIG9mIEludGVybmV0IFVzYWdlIGJ5IFN0YXRlIGFuZCBBdmVyYWdlIEluY29tZSBieSBTdGF0ZSBmb3IgdGhlIFllYXJzIDIwMDcvMjAxMg0KICAgICAgICBiKQlSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYWxlIHRvIEZlbWFsZSBSYXRpbyBhbmQgSW50ZXJuZXQgUGVuZXRyYXRpb24gKEJsZW5kaW5nIERhdGEgKyBJZmVsc2UgKyBMT0QgKQ0KICAgIEUpCUxlYWQvTGFnDQogICAgICAgIGEpCURpZmZlcmVuY2UgaW4gSW5jb21lIGJ5IFN0YXRlIGZvciAyMDA3LTIwMTINCiAgICBGKQlQZXJjZW50IFJhbmsNCiAgICAgICAgYSkJQ29ycmVsYXRpb24gQmV0d2VlbiBBdmVyYWdlIEhvdXNlaG9sZCBJbmNvbWUgYW5kIEludGVybmV0IFBlbmV0cmF0aW9uDQogICAgRykgIE90aGVyDQogICAgICAgIGEpICBHZW5kZXIgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24NCiAgICAgICAgICAgIFlvdW5nZXIgQWdlIEdyb3VwICgxNS0yOSkgVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24NCiAgICAgICAgICAgIEVsZGVybHkgQWdlIEdyb3VwICg2MC04NSspIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQoyNSkJUGFja2VkIEJ1YmJsZXMNCiAgICBBKQlJbnRlcm5ldCBVc2FnZSBhdCBIb21lIGFuZCBpdHMgQ29ycmVsYXRpb24gd2l0aCB0aGUgNjUtNjktWWVhci1PbGQgUG9wdWxhdGlvbg0KMjYpCVBhcmFtZXRlcg0KICAgIEEpCUxldmVscyBvZiBJbnRlcm5ldCBVc2FnZSBieSBTdGF0ZSBhbmQgQXZlcmFnZSBJbmNvbWUgYnkgU3RhdGUgZm9yIHRoZSBZZWFycyAyMDA3LzIwMTINCiAgICBCKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiBhbmQgSG91c2Vob2xkIEludGVybmV0IFVzYWdlIOKAkyAyMDA3DQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KMjcpCVBvc2l0aW9uDQogICAgQSkJUGVyY2VudCBvZiBJbmRpdmlkdWFscyBXaG8gQWNjZXNzZWQgdGhlIEludGVybmV0IGZyb20gSG9tZSBpbiAyMDA3IGFuZCAyMDEyDQogICAgQikgIEdlbmRlciBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg0KICAgICAgICBZb3VuZ2VyIEFnZSBHcm91cCAoMTUtMjkpIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQogICAgICAgIEVsZGVybHkgQWdlIEdyb3VwICg2MC04NSspIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQoyOCkJUmVhZCBDU1YNCiAgICBBKQlJbnB1dHRpbmcgYW5kIENsZWFuaW5nIHRoZSBDU1ZzDQoyOSkJUmVndWxhciBFeHByZXNzaW9ucw0KICAgIEEpCUlucHV0dGluZyBhbmQgQ2xlYW5pbmcgdGhlIENTVnMNCiAgICBCKQlEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgICAgIEludGVybmV0IFVzYWdlIGF0IEhvbWUgYW5kIGl0cyBDb3JyZWxhdGlvbiB3aXRoIHRoZSA2NS02OS1ZZWFyLU9sZCBQb3B1bGF0aW9uDQogICAgQykJUmVsYXRpb25zaGlwIEJldHdlZW4gSW5jb21lIGFuZCBVc2VycyBBY2Nlc3NpbmcgSW50ZXJuZXQgT3V0c2lkZSBIb21lIGZyb20gMjAwNyB0byAyMDEyDQogICAgICAgIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIE1hbGUgdG8gRmVtYWxlIFJhdGlvIGFuZCBJbnRlcm5ldCBQZW5ldHJhdGlvbiAoQmxlbmRpbmcgRGF0YSArIElmZWxzZSArIExPRCApDQozMCkJU2NhdHRlciBQbG90DQogICAgQSkJRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIGl0cyBSZWxhdGlvbnNoaXAgdG8gQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lDQogICAgICAgIENvcnJlbGF0aW9uIEJldHdlZW4gQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIGFuZCBJbnRlcm5ldCBQZW5ldHJhdGlvbg0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2Ug4oCTIDIwMDcNCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gTWFsZSB0byBGZW1hbGUgUmF0aW8gYW5kIEludGVybmV0IFBlbmV0cmF0aW9uIChCbGVuZGluZyBEYXRhICsgSWZlbHNlICsgTE9EICkNCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gSW4taG9tZSBhbmQgT3V0IG9mIEhvbWUgSW50ZXJuZXQgQWNjZXNzIGZvciAyMDA3LzIwMTINCiAgICAgICAgUmVsYXRpb25zaGlwIGJldHdlZW4gTWF4aW11bSBEaXNjcmVwYW5jeSBvZiBJbnRlcm5ldCBBY2Nlc3MgT3V0c2lkZSBIb3VzZWhvbGQgYW5kIEluY29tZSBCcmFja2V0cw0KICAgIEMpCVJlbGF0aW9ucyBiZXR3ZWVuIGludGVybmV0IHVzYWdlIGF0IGhvbWUgdmVyc3VzIGludGVybmV0IHVzYWdlIG91dHNpZGUgb2YgdGhlIGhvbWUgZnJvbSAyMDA3IHRvIDIwMTINCiAgICAgICAgRmFjZWJvb2sgdXNlcnMgdnMgbW9kZSBvZiBJbnRlcm5ldCB1c2FnZSBpbiAyMDA3DQogICAgRCkgIEludGVybmV0IEFjY2VzcyBWcyBBdmVyYWdlIEluY29tZSBSZXNwZWN0aXZlIHRvIDIwMDcgYW5kIDIwMTINCiAgICAgICAgR2VuZGVyIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQogICAgICAgIEludGVybmV0IEFjY2VzcyBWcyBBdmVyYWdlIEluY29tZSBSZXNwZWN0aXZlIHRvIDIwMDcgYW5kIDIwMTINCiAgICAgICAgSW50ZXJuZXQgUGVuZXRyYXRpb24gVnMgRmFjZWJvb2sgUGVuZXRyYXRpb24gVnMgSW50ZXJuZXQgQWNjZXNzDQozMSkJU2VsZWN0IChTUUwpIOKAkyBmb3VuZCBpbiBldmVyeSBpbnNpZ2h0DQozMikJU2VsZWN0IChkcGx5cikNCiAgICBBKQlEaWZmZXJlbmNlIGluIEluY29tZSBieSBTdGF0ZSBmb3IgMjAwNy0yMDEyDQogICAgICAgIEludGVybmV0IFVzYWdlIGF0IEhvbWUgYW5kIGl0cyBDb3JyZWxhdGlvbiB3aXRoIHRoZSA2NS02OS1ZZWFyLU9sZCBQb3B1bGF0aW9uDQogICAgICAgIEZhY2Vib29rIFBlbmV0cmF0aW9uIGZvciAxNS0xOSBZZWFyIE9sZHMgVmVyc3VzIDQwLTQ0IFllYXIgT2xkcw0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1pbGxlbm5pYWwgUG9wdWxhdGlvbiBhbmQgSW50ZXJuZXQgQWNjZXNzDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEluY29tZSBhbmQgVXNlcnMgQWNjZXNzaW5nIEludGVybmV0IE91dHNpZGUgSG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KICAgICAgICBSZWxhdGlvbnNoaXAgYmV0d2VlbiBNYWxlIHRvIEZlbWFsZSBSYXRpbyBhbmQgSW50ZXJuZXQgUGVuZXRyYXRpb24gKEJsZW5kaW5nIERhdGEgKyBJZmVsc2UgKyBMT0QgKQ0KICAgIEMpCVRyZW5kcyBpbiBwZXJjZW50IGNoYW5nZXMgYmV0d2VlbiAyMDA3IGFuZCAyMDEyIGJ5IHN0YXRlIG9mIGhvdXNlaG9sZCBpbmNvbWUgYW5kIGhvbWUgaW50ZXJuZXQgdXNhZ2UNCiAgICAgICAgUmVsYXRpb25zIGJldHdlZW4gaW50ZXJuZXQgdXNhZ2UgYXQgaG9tZSB2ZXJzdXMgaW50ZXJuZXQgdXNhZ2Ugb3V0c2lkZSBvZiB0aGUgaG9tZSBmcm9tIDIwMDcgdG8gMjAxMg0KMzMpCVNldCAoVGFibGVhdSkNCiAgICBBKQlMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIEJldHdlZW4gRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIEhvdXNlaG9sZCBJbnRlcm5ldCBVc2FnZSAtIDIwMDcNCjM0KQlTdGF0DQogICAgQSkgIExldmVscyBvZiBJbnRlcm5ldCBVc2FnZSBieSBTdGF0ZSBhbmQgQXZlcmFnZSBJbmNvbWUgYnkgU3RhdGUgZm9yIHRoZSBZZWFycyAyMDA3LzIwMTINCiAgICAgICAgRGlmZmVyZW5jZSBpbiBJbmNvbWUgYnkgU3RhdGUgZm9yIDIwMDctMjAxMg0KICAgICAgICBGYWNlYm9vayBQZW5ldHJhdGlvbiBmb3IgMTUtMTkgWWVhciBPbGRzIFZlcnN1cyA0MC00NCBZZWFyIE9sZHMNCiAgICBCKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBNaWxsZW5uaWFsIFBvcHVsYXRpb24gYW5kIEludGVybmV0IEFjY2Vzcw0KICAgICAgICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBJbmNvbWUgYW5kIFVzZXJzIEFjY2Vzc2luZyBJbnRlcm5ldCBPdXRzaWRlIEhvbWUgZnJvbSAyMDA3IHRvIDIwMTINCiAgICAgICAgUmVsYXRpb25zaGlwIEJldHdlZW4gRmFjZWJvb2sgUGVuZXRyYXRpb24gYW5kIEhvdXNlaG9sZCBJbnRlcm5ldCBVc2FnZSDigJMgMjAwNw0KICAgIEMpICBUcmVuZHMgaW4gcGVyY2VudCBjaGFuZ2VzIGJldHdlZW4gMjAwNyBhbmQgMjAxMiBieSBzdGF0ZSBvZiBob3VzZWhvbGQgaW5jb21lIGFuZCBob21lIGludGVybmV0IHVzYWdlICAgICAgICAgICAgICAgICBGYWNlYm9vayB1c2VycyB2cyBtb2RlIG9mIEludGVybmV0IHVzYWdlIGluIDIwMDcNCiAgICAgICAgRmFjZWJvb2sgdXNlcnMgdnMgbW9kZSBvZiBJbnRlcm5ldCB1c2FnZSBpbiAyMDEyDQogICAgICAgIEdlbmRlciBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg0KICAgICAgICBZb3VuZ2VyIEFnZSBHcm91cCAoMTUtMjkpIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQogICAgICAgIEVsZGVybHkgQWdlIEdyb3VwICg2MC04NSspIFZzIEZhY2Vib29rIFBlbmV0cmF0aW9uDQozNSkJU3VicXVlcmllcw0KICAgIEEpICBMZXZlbHMgb2YgSW50ZXJuZXQgVXNhZ2UgYnkgU3RhdGUgYW5kIEF2ZXJhZ2UgSW5jb21lIGJ5IFN0YXRlIGZvciB0aGUgWWVhcnMgMjAwNy8yMDEyDQogICAgQikJUmVsYXRpb25zaGlwIEJldHdlZW4gSW5jb21lIGFuZCBVc2VycyBBY2Nlc3NpbmcgSW50ZXJuZXQgT3V0c2lkZSBIb21lIGZyb20gMjAwNyB0byAyMDEyDQogICAgICAgIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2UgLSAyMDA3DQozNikJU3VtbWFyaXplDQogICAgQSkJTWVhbg0KICAgICAgICBhKQlQZXJjZW50IG9mIEluZGl2aWR1YWxzIFdobyBBY2Nlc3NlZCBUaGUgSW50ZXJuZXQgZnJvbSBIb21lIGluIDIwMDcgYW5kIDIwMTINCiAgICAgICAgYikJUmVsYXRpb25zaGlwIEJldHdlZW4gTWlsbGVubmlhbCBQb3B1bGF0aW9uIGFuZCBJbnRlcm5ldCBBY2Nlc3MNCiAgICBCKQlNZWRpYW4NCiAgICAgICAgYSkJUmVsYXRpb25zaGlwIGJldHdlZW4gSW4taG9tZSBhbmQgT3V0IG9mIEhvbWUgSW50ZXJuZXQgQWNjZXNzIGZvciAyMDA3LzIwMTINCjM3KQlUYWJsZSBDYWxjdWxhdGlvbg0KICAgIEEpCUNvcnJlbGF0aW9uIEJldHdlZW4gQXZlcmFnZSBIb3VzZWhvbGQgSW5jb21lIGFuZCBJbnRlcm5ldCBQZW5ldHJhdGlvbg0KICAgIEIpCVJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZhY2Vib29rIFBlbmV0cmF0aW9uIGFuZCBIb3VzZWhvbGQgSW50ZXJuZXQgVXNhZ2UgLSAyMDA3DQozOCkJVGliYmxlIOKAkyBmb3VuZCBpbiBldmVyeSBpbnNpZ2h0DQozOSkJVHJlZSBNYXANCiAgICBBKQlSZWxhdGlvbnNoaXAgQmV0d2VlbiBGYWNlYm9vayBQZW5ldHJhdGlvbiwgSW50ZXJuZXQgUGVuZXRyYXRpb24sIGFuZCAyMC0yNCBQb3B1bGF0aW9uIC0gMjAxMg0KICAgIEIpICBFbGRlcmx5IEFnZSBHcm91cCAoNjAtODUrKSBWcyBGYWNlYm9vayBQZW5ldHJhdGlvbg==